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](false));
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](false));
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](true));
241 // then add the element..
249 if (typeof (tree.menu) != 'undefined') {
250 tree.menu.parentType = cn.xtype;
251 tree.menu.triggerEl = cn.el;
252 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
256 if (!tree.items || !tree.items.length) {
260 var items = tree.items;
263 //Roo.log(items.length);
265 for(var i =0;i < items.length;i++) {
266 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
287 * @class Roo.bootstrap.Body
288 * @extends Roo.bootstrap.Component
289 * Bootstrap Body class
293 * @param {Object} config The config object
296 Roo.bootstrap.Body = function(config){
297 Roo.bootstrap.Body.superclass.constructor.call(this, config);
298 this.el = Roo.get(document.body);
299 if (this.cls && this.cls.length) {
300 Roo.get(document.body).addClass(this.cls);
304 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
309 onRender : function(ct, position)
311 /* Roo.log("Roo.bootstrap.Body - onRender");
312 if (this.cls && this.cls.length) {
313 Roo.get(document.body).addClass(this.cls);
333 * @class Roo.bootstrap.ButtonGroup
334 * @extends Roo.bootstrap.Component
335 * Bootstrap ButtonGroup class
336 * @cfg {String} size lg | sm | xs (default empty normal)
337 * @cfg {String} align vertical | justified (default none)
338 * @cfg {String} direction up | down (default down)
339 * @cfg {Boolean} toolbar false | true
340 * @cfg {Boolean} btn true | false
345 * @param {Object} config The config object
348 Roo.bootstrap.ButtonGroup = function(config){
349 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
352 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
360 getAutoCreate : function(){
366 cfg.html = this.html || cfg.html;
377 if (['vertical','justified'].indexOf(this.align)!==-1) {
378 cfg.cls = 'btn-group-' + this.align;
380 if (this.align == 'justified') {
381 console.log(this.items);
385 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
386 cfg.cls += ' btn-group-' + this.size;
389 if (this.direction == 'up') {
390 cfg.cls += ' dropup' ;
406 * @class Roo.bootstrap.Button
407 * @extends Roo.bootstrap.Component
408 * Bootstrap Button class
409 * @cfg {String} html The button content
410 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
411 * @cfg {String} size empty | lg | sm | xs
412 * @cfg {String} tag empty | a | input | submit
413 * @cfg {String} href empty or href
414 * @cfg {Boolean} disabled false | true
415 * @cfg {Boolean} isClose false | true
416 * @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
417 * @cfg {String} badge text for badge
418 * @cfg {String} theme default (or empty) | glow
419 * @cfg {Boolean} inverse false | true
420 * @cfg {Boolean} toggle false | true
421 * @cfg {String} ontext text for on toggle state
422 * @cfg {String} offtext text for off toggle state
423 * @cfg {Boolean} defaulton true | false
424 * @cfg {Boolean} preventDefault (true | false) default true
425 * @cfg {Boolean} removeClass true | false remove the standard class..
426 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
429 * Create a new button
430 * @param {Object} config The config object
434 Roo.bootstrap.Button = function(config){
435 Roo.bootstrap.Button.superclass.constructor.call(this, config);
440 * When a butotn is pressed
441 * @param {Roo.EventObject} e
446 * After the button has been toggles
447 * @param {Roo.EventObject} e
448 * @param {boolean} pressed (also available as button.pressed)
454 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
472 preventDefault: true,
481 getAutoCreate : function(){
489 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
490 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
495 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
497 if (this.toggle == true) {
500 cls: 'slider-frame roo-button',
505 'data-off-text':'OFF',
506 cls: 'slider-button',
512 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
513 cfg.cls += ' '+this.weight;
522 cfg["aria-hidden"] = true;
524 cfg.html = "×";
530 if (this.theme==='default') {
531 cfg.cls = 'btn roo-button';
533 //if (this.parentType != 'Navbar') {
534 this.weight = this.weight.length ? this.weight : 'default';
536 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
538 cfg.cls += ' btn-' + this.weight;
540 } else if (this.theme==='glow') {
543 cfg.cls = 'btn-glow roo-button';
545 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
547 cfg.cls += ' ' + this.weight;
553 this.cls += ' inverse';
558 cfg.cls += ' active';
562 cfg.disabled = 'disabled';
566 Roo.log('changing to ul' );
568 this.glyphicon = 'caret';
571 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
573 //gsRoo.log(this.parentType);
574 if (this.parentType === 'Navbar' && !this.parent().bar) {
575 Roo.log('changing to li?');
584 href : this.href || '#'
587 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
588 cfg.cls += ' dropdown';
595 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
597 if (this.glyphicon) {
598 cfg.html = ' ' + cfg.html;
603 cls: 'glyphicon glyphicon-' + this.glyphicon
613 // cfg.cls='btn roo-button';
617 var value = cfg.html;
622 cls: 'glyphicon glyphicon-' + this.glyphicon,
641 cfg.cls += ' dropdown';
642 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
645 if (cfg.tag !== 'a' && this.href !== '') {
646 throw "Tag must be a to set href.";
647 } else if (this.href.length > 0) {
648 cfg.href = this.href;
651 if(this.removeClass){
656 cfg.target = this.target;
661 initEvents: function() {
662 // Roo.log('init events?');
663 // Roo.log(this.el.dom);
666 if (typeof (this.menu) != 'undefined') {
667 this.menu.parentType = this.xtype;
668 this.menu.triggerEl = this.el;
669 this.addxtype(Roo.apply({}, this.menu));
673 if (this.el.hasClass('roo-button')) {
674 this.el.on('click', this.onClick, this);
676 this.el.select('.roo-button').on('click', this.onClick, this);
679 if(this.removeClass){
680 this.el.on('click', this.onClick, this);
683 this.el.enableDisplayMode();
686 onClick : function(e)
692 Roo.log('button on click ');
693 if(this.preventDefault){
696 if (this.pressed === true || this.pressed === false) {
697 this.pressed = !this.pressed;
698 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
699 this.fireEvent('toggle', this, e, this.pressed);
703 this.fireEvent('click', this, e);
707 * Enables this button
711 this.disabled = false;
712 this.el.removeClass('disabled');
716 * Disable this button
720 this.disabled = true;
721 this.el.addClass('disabled');
724 * sets the active state on/off,
725 * @param {Boolean} state (optional) Force a particular state
727 setActive : function(v) {
729 this.el[v ? 'addClass' : 'removeClass']('active');
732 * toggles the current active state
734 toggleActive : function()
736 var active = this.el.hasClass('active');
737 this.setActive(!active);
741 setText : function(str)
743 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
747 return this.el.select('.roo-button-text',true).first().dom.innerHTML;
770 * @class Roo.bootstrap.Column
771 * @extends Roo.bootstrap.Component
772 * Bootstrap Column class
773 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
774 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
775 * @cfg {Number} md colspan out of 12 for computer-sized screens
776 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
777 * @cfg {String} html content of column.
780 * Create a new Column
781 * @param {Object} config The config object
784 Roo.bootstrap.Column = function(config){
785 Roo.bootstrap.Column.superclass.constructor.call(this, config);
788 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
797 getAutoCreate : function(){
798 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
806 ['xs','sm','md','lg'].map(function(size){
807 if (settings[size]) {
808 cfg.cls += ' col-' + size + '-' + settings[size];
811 if (this.html.length) {
812 cfg.html = this.html;
831 * @class Roo.bootstrap.Container
832 * @extends Roo.bootstrap.Component
833 * Bootstrap Container class
834 * @cfg {Boolean} jumbotron is it a jumbotron element
835 * @cfg {String} html content of element
836 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
837 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
838 * @cfg {String} header content of header (for panel)
839 * @cfg {String} footer content of footer (for panel)
840 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
841 * @cfg {String} tag (header|aside|section) type of HTML tag.
845 * Create a new Container
846 * @param {Object} config The config object
849 Roo.bootstrap.Container = function(config){
850 Roo.bootstrap.Container.superclass.constructor.call(this, config);
853 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
864 getChildContainer : function() {
870 if (this.panel.length) {
871 return this.el.select('.panel-body',true).first();
878 getAutoCreate : function(){
881 tag : this.tag || 'div',
885 if (this.jumbotron) {
886 cfg.cls = 'jumbotron';
888 // - this is applied by the parent..
890 // cfg.cls = this.cls + '';
893 if (this.sticky.length) {
895 var bd = Roo.get(document.body);
896 if (!bd.hasClass('bootstrap-sticky')) {
897 bd.addClass('bootstrap-sticky');
898 Roo.select('html',true).setStyle('height', '100%');
901 cfg.cls += 'bootstrap-sticky-' + this.sticky;
905 if (this.well.length) {
909 cfg.cls +=' well well-' +this.well;
919 if (this.panel.length) {
920 cfg.cls += ' panel panel-' + this.panel;
922 if (this.header.length) {
925 cls : 'panel-heading',
941 if (this.footer.length) {
943 cls : 'panel-footer',
952 body.html = this.html || cfg.html;
954 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
955 cfg.cls = 'container';
963 if(!this.el || !this.panel.length || !this.header.length){
967 return this.el.select('.panel-title',true).first();
970 setTitle : function(v)
972 var titleEl = this.titleEl();
978 titleEl.dom.innerHTML = v;
981 getTitle : function()
984 var titleEl = this.titleEl();
990 return titleEl.dom.innerHTML;
1004 * @class Roo.bootstrap.Img
1005 * @extends Roo.bootstrap.Component
1006 * Bootstrap Img class
1007 * @cfg {Boolean} imgResponsive false | true
1008 * @cfg {String} border rounded | circle | thumbnail
1009 * @cfg {String} src image source
1010 * @cfg {String} alt image alternative text
1011 * @cfg {String} href a tag href
1012 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
1015 * Create a new Input
1016 * @param {Object} config The config object
1019 Roo.bootstrap.Img = function(config){
1020 Roo.bootstrap.Img.superclass.constructor.call(this, config);
1026 * The img click event for the img.
1027 * @param {Roo.EventObject} e
1033 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
1035 imgResponsive: true,
1041 getAutoCreate : function(){
1045 cls: (this.imgResponsive) ? 'img-responsive' : '',
1049 cfg.html = this.html || cfg.html;
1051 cfg.src = this.src || cfg.src;
1053 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1054 cfg.cls += ' img-' + this.border;
1071 a.target = this.target;
1077 return (this.href) ? a : cfg;
1080 initEvents: function() {
1083 this.el.on('click', this.onClick, this);
1087 onClick : function(e)
1089 Roo.log('img onclick');
1090 this.fireEvent('click', this, e);
1104 * @class Roo.bootstrap.Link
1105 * @extends Roo.bootstrap.Component
1106 * Bootstrap Link Class
1107 * @cfg {String} alt image alternative text
1108 * @cfg {String} href a tag href
1109 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1110 * @cfg {String} html the content of the link.
1111 * @cfg {Boolean} preventDefault (true | false) default false
1115 * Create a new Input
1116 * @param {Object} config The config object
1119 Roo.bootstrap.Link = function(config){
1120 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1126 * The img click event for the img.
1127 * @param {Roo.EventObject} e
1133 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1137 preventDefault: false,
1139 getAutoCreate : function(){
1143 html : this.html || 'html-missing'
1150 cfg.href = this.href || '#';
1152 cfg.target = this.target;
1158 initEvents: function() {
1161 this.el.on('click', this.onClick, this);
1165 onClick : function(e)
1167 if(this.preventDefault){
1170 //Roo.log('img onclick');
1171 this.fireEvent('click', this, e);
1184 * @class Roo.bootstrap.Header
1185 * @extends Roo.bootstrap.Component
1186 * Bootstrap Header class
1187 * @cfg {String} html content of header
1188 * @cfg {Number} level (1|2|3|4|5|6) default 1
1191 * Create a new Header
1192 * @param {Object} config The config object
1196 Roo.bootstrap.Header = function(config){
1197 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1200 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1208 getAutoCreate : function(){
1211 tag: 'h' + (1 *this.level),
1212 html: this.html || 'fill in html'
1224 * Ext JS Library 1.1.1
1225 * Copyright(c) 2006-2007, Ext JS, LLC.
1227 * Originally Released Under LGPL - original licence link has changed is not relivant.
1230 * <script type="text/javascript">
1234 * @class Roo.bootstrap.MenuMgr
1235 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1238 Roo.bootstrap.MenuMgr = function(){
1239 var menus, active, groups = {}, attached = false, lastShow = new Date();
1241 // private - called when first menu is created
1244 active = new Roo.util.MixedCollection();
1245 Roo.get(document).addKeyListener(27, function(){
1246 if(active.length > 0){
1254 if(active && active.length > 0){
1255 var c = active.clone();
1265 if(active.length < 1){
1266 Roo.get(document).un("mouseup", onMouseDown);
1274 var last = active.last();
1275 lastShow = new Date();
1278 Roo.get(document).on("mouseup", onMouseDown);
1283 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1284 m.parentMenu.activeChild = m;
1285 }else if(last && last.isVisible()){
1286 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1291 function onBeforeHide(m){
1293 m.activeChild.hide();
1295 if(m.autoHideTimer){
1296 clearTimeout(m.autoHideTimer);
1297 delete m.autoHideTimer;
1302 function onBeforeShow(m){
1303 var pm = m.parentMenu;
1304 if(!pm && !m.allowOtherMenus){
1306 }else if(pm && pm.activeChild && active != m){
1307 pm.activeChild.hide();
1312 function onMouseDown(e){
1313 Roo.log("on MouseDown");
1314 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1322 function onBeforeCheck(mi, state){
1324 var g = groups[mi.group];
1325 for(var i = 0, l = g.length; i < l; i++){
1327 g[i].setChecked(false);
1336 * Hides all menus that are currently visible
1338 hideAll : function(){
1343 register : function(menu){
1347 menus[menu.id] = menu;
1348 menu.on("beforehide", onBeforeHide);
1349 menu.on("hide", onHide);
1350 menu.on("beforeshow", onBeforeShow);
1351 menu.on("show", onShow);
1353 if(g && menu.events["checkchange"]){
1357 groups[g].push(menu);
1358 menu.on("checkchange", onCheck);
1363 * Returns a {@link Roo.menu.Menu} object
1364 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1365 * be used to generate and return a new Menu instance.
1367 get : function(menu){
1368 if(typeof menu == "string"){ // menu id
1370 }else if(menu.events){ // menu instance
1373 /*else if(typeof menu.length == 'number'){ // array of menu items?
1374 return new Roo.bootstrap.Menu({items:menu});
1375 }else{ // otherwise, must be a config
1376 return new Roo.bootstrap.Menu(menu);
1383 unregister : function(menu){
1384 delete menus[menu.id];
1385 menu.un("beforehide", onBeforeHide);
1386 menu.un("hide", onHide);
1387 menu.un("beforeshow", onBeforeShow);
1388 menu.un("show", onShow);
1390 if(g && menu.events["checkchange"]){
1391 groups[g].remove(menu);
1392 menu.un("checkchange", onCheck);
1397 registerCheckable : function(menuItem){
1398 var g = menuItem.group;
1403 groups[g].push(menuItem);
1404 menuItem.on("beforecheckchange", onBeforeCheck);
1409 unregisterCheckable : function(menuItem){
1410 var g = menuItem.group;
1412 groups[g].remove(menuItem);
1413 menuItem.un("beforecheckchange", onBeforeCheck);
1425 * @class Roo.bootstrap.Menu
1426 * @extends Roo.bootstrap.Component
1427 * Bootstrap Menu class - container for MenuItems
1428 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1432 * @param {Object} config The config object
1436 Roo.bootstrap.Menu = function(config){
1437 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1438 if (this.registerMenu) {
1439 Roo.bootstrap.MenuMgr.register(this);
1444 * Fires before this menu is displayed
1445 * @param {Roo.menu.Menu} this
1450 * Fires before this menu is hidden
1451 * @param {Roo.menu.Menu} this
1456 * Fires after this menu is displayed
1457 * @param {Roo.menu.Menu} this
1462 * Fires after this menu is hidden
1463 * @param {Roo.menu.Menu} this
1468 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1469 * @param {Roo.menu.Menu} this
1470 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1471 * @param {Roo.EventObject} e
1476 * Fires when the mouse is hovering over this menu
1477 * @param {Roo.menu.Menu} this
1478 * @param {Roo.EventObject} e
1479 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1484 * Fires when the mouse exits this menu
1485 * @param {Roo.menu.Menu} this
1486 * @param {Roo.EventObject} e
1487 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1492 * Fires when a menu item contained in this menu is clicked
1493 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1494 * @param {Roo.EventObject} e
1498 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1501 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1505 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1508 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1510 registerMenu : true,
1512 menuItems :false, // stores the menu items..
1518 getChildContainer : function() {
1522 getAutoCreate : function(){
1524 //if (['right'].indexOf(this.align)!==-1) {
1525 // cfg.cn[1].cls += ' pull-right'
1531 cls : 'dropdown-menu' ,
1532 style : 'z-index:1000'
1536 if (this.type === 'submenu') {
1537 cfg.cls = 'submenu active';
1539 if (this.type === 'treeview') {
1540 cfg.cls = 'treeview-menu';
1545 initEvents : function() {
1547 // Roo.log("ADD event");
1548 // Roo.log(this.triggerEl.dom);
1549 this.triggerEl.on('click', this.onTriggerPress, this);
1550 this.triggerEl.addClass('dropdown-toggle');
1551 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1553 this.el.on("mouseover", this.onMouseOver, this);
1554 this.el.on("mouseout", this.onMouseOut, this);
1558 findTargetItem : function(e){
1559 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1563 //Roo.log(t); Roo.log(t.id);
1565 //Roo.log(this.menuitems);
1566 return this.menuitems.get(t.id);
1568 //return this.items.get(t.menuItemId);
1573 onClick : function(e){
1574 Roo.log("menu.onClick");
1575 var t = this.findTargetItem(e);
1581 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1582 if(t == this.activeItem && t.shouldDeactivate(e)){
1583 this.activeItem.deactivate();
1584 delete this.activeItem;
1588 this.setActiveItem(t, true);
1595 Roo.log('pass click event');
1599 this.fireEvent("click", this, t, e);
1603 onMouseOver : function(e){
1604 var t = this.findTargetItem(e);
1607 // if(t.canActivate && !t.disabled){
1608 // this.setActiveItem(t, true);
1612 this.fireEvent("mouseover", this, e, t);
1614 isVisible : function(){
1615 return !this.hidden;
1617 onMouseOut : function(e){
1618 var t = this.findTargetItem(e);
1621 // if(t == this.activeItem && t.shouldDeactivate(e)){
1622 // this.activeItem.deactivate();
1623 // delete this.activeItem;
1626 this.fireEvent("mouseout", this, e, t);
1631 * Displays this menu relative to another element
1632 * @param {String/HTMLElement/Roo.Element} element The element to align to
1633 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1634 * the element (defaults to this.defaultAlign)
1635 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1637 show : function(el, pos, parentMenu){
1638 this.parentMenu = parentMenu;
1642 this.fireEvent("beforeshow", this);
1643 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1646 * Displays this menu at a specific xy position
1647 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1648 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1650 showAt : function(xy, parentMenu, /* private: */_e){
1651 this.parentMenu = parentMenu;
1656 this.fireEvent("beforeshow", this);
1658 //xy = this.el.adjustForConstraints(xy);
1660 //this.el.setXY(xy);
1662 this.hideMenuItems();
1663 this.hidden = false;
1664 this.triggerEl.addClass('open');
1666 this.fireEvent("show", this);
1672 this.doFocus.defer(50, this);
1676 doFocus : function(){
1678 this.focusEl.focus();
1683 * Hides this menu and optionally all parent menus
1684 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1686 hide : function(deep){
1688 this.hideMenuItems();
1689 if(this.el && this.isVisible()){
1690 this.fireEvent("beforehide", this);
1691 if(this.activeItem){
1692 this.activeItem.deactivate();
1693 this.activeItem = null;
1695 this.triggerEl.removeClass('open');;
1697 this.fireEvent("hide", this);
1699 if(deep === true && this.parentMenu){
1700 this.parentMenu.hide(true);
1704 onTriggerPress : function(e)
1707 Roo.log('trigger press');
1708 //Roo.log(e.getTarget());
1709 // Roo.log(this.triggerEl.dom);
1710 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1713 if (this.isVisible()) {
1717 this.show(this.triggerEl, false, false);
1726 hideMenuItems : function()
1728 //$(backdrop).remove()
1729 Roo.select('.open',true).each(function(aa) {
1731 aa.removeClass('open');
1732 //var parent = getParent($(this))
1733 //var relatedTarget = { relatedTarget: this }
1735 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1736 //if (e.isDefaultPrevented()) return
1737 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1740 addxtypeChild : function (tree, cntr) {
1741 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1743 this.menuitems.add(comp);
1764 * @class Roo.bootstrap.MenuItem
1765 * @extends Roo.bootstrap.Component
1766 * Bootstrap MenuItem class
1767 * @cfg {String} html the menu label
1768 * @cfg {String} href the link
1769 * @cfg {Boolean} preventDefault (true | false) default true
1773 * Create a new MenuItem
1774 * @param {Object} config The config object
1778 Roo.bootstrap.MenuItem = function(config){
1779 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1784 * The raw click event for the entire grid.
1785 * @param {Roo.EventObject} e
1791 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1795 preventDefault: true,
1797 getAutoCreate : function(){
1800 cls: 'dropdown-menu-item',
1809 if (this.parent().type == 'treeview') {
1810 cfg.cls = 'treeview-menu';
1813 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1814 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1818 initEvents: function() {
1820 //this.el.select('a').on('click', this.onClick, this);
1823 onClick : function(e)
1825 Roo.log('item on click ');
1826 //if(this.preventDefault){
1827 // e.preventDefault();
1829 //this.parent().hideMenuItems();
1831 this.fireEvent('click', this, e);
1850 * @class Roo.bootstrap.MenuSeparator
1851 * @extends Roo.bootstrap.Component
1852 * Bootstrap MenuSeparator class
1855 * Create a new MenuItem
1856 * @param {Object} config The config object
1860 Roo.bootstrap.MenuSeparator = function(config){
1861 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1864 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1866 getAutoCreate : function(){
1881 <div class="modal fade">
1882 <div class="modal-dialog">
1883 <div class="modal-content">
1884 <div class="modal-header">
1885 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1886 <h4 class="modal-title">Modal title</h4>
1888 <div class="modal-body">
1889 <p>One fine body…</p>
1891 <div class="modal-footer">
1892 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1893 <button type="button" class="btn btn-primary">Save changes</button>
1895 </div><!-- /.modal-content -->
1896 </div><!-- /.modal-dialog -->
1897 </div><!-- /.modal -->
1907 * @class Roo.bootstrap.Modal
1908 * @extends Roo.bootstrap.Component
1909 * Bootstrap Modal class
1910 * @cfg {String} title Title of dialog
1911 * @cfg {Boolean} specificTitle (true|false) default false
1912 * @cfg {Array} buttons Array of buttons or standard button set..
1913 * @cfg {String} buttonPosition (left|right|center) default right
1916 * Create a new Modal Dialog
1917 * @param {Object} config The config object
1920 Roo.bootstrap.Modal = function(config){
1921 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1926 * The raw btnclick event for the button
1927 * @param {Roo.EventObject} e
1931 this.buttons = this.buttons || [];
1934 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1936 title : 'test dialog',
1943 specificTitle: false,
1945 buttonPosition: 'right',
1947 onRender : function(ct, position)
1949 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1952 var cfg = Roo.apply({}, this.getAutoCreate());
1955 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1957 //if (!cfg.name.length) {
1961 cfg.cls += ' ' + this.cls;
1964 cfg.style = this.style;
1966 this.el = Roo.get(document.body).createChild(cfg, position);
1968 //var type = this.el.dom.type;
1970 if(this.tabIndex !== undefined){
1971 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1976 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1977 this.maskEl.enableDisplayMode("block");
1979 //this.el.addClass("x-dlg-modal");
1981 if (this.buttons.length) {
1982 Roo.each(this.buttons, function(bb) {
1983 b = Roo.apply({}, bb);
1984 b.xns = b.xns || Roo.bootstrap;
1985 b.xtype = b.xtype || 'Button';
1986 if (typeof(b.listeners) == 'undefined') {
1987 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1990 var btn = Roo.factory(b);
1992 btn.onRender(this.el.select('.modal-footer div').first());
1996 // render the children.
1999 if(typeof(this.items) != 'undefined'){
2000 var items = this.items;
2003 for(var i =0;i < items.length;i++) {
2004 nitems.push(this.addxtype(Roo.apply({}, items[i])));
2008 this.items = nitems;
2010 this.body = this.el.select('.modal-body',true).first();
2011 this.close = this.el.select('.modal-header .close', true).first();
2012 this.footer = this.el.select('.modal-footer',true).first();
2014 //this.el.addClass([this.fieldClass, this.cls]);
2017 getAutoCreate : function(){
2022 html : this.html || ''
2027 cls : 'modal-title',
2031 if(this.specificTitle){
2037 style : 'display: none',
2040 cls: "modal-dialog",
2043 cls : "modal-content",
2046 cls : 'modal-header',
2058 cls : 'modal-footer',
2062 cls: 'btn-' + this.buttonPosition
2081 getChildContainer : function() {
2083 return this.el.select('.modal-body',true).first();
2086 getButtonContainer : function() {
2087 return this.el.select('.modal-footer div',true).first();
2090 initEvents : function()
2092 this.el.select('.modal-header .close').on('click', this.hide, this);
2094 // this.addxtype(this);
2098 if (!this.rendered) {
2102 this.el.addClass('on');
2103 this.el.removeClass('fade');
2104 this.el.setStyle('display', 'block');
2105 Roo.get(document.body).addClass("x-body-masked");
2106 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2108 this.el.setStyle('zIndex', '10001');
2109 this.fireEvent('show', this);
2115 Roo.log('Modal hide?!');
2117 Roo.get(document.body).removeClass("x-body-masked");
2118 this.el.removeClass('on');
2119 this.el.addClass('fade');
2120 this.el.setStyle('display', 'none');
2121 this.fireEvent('hide', this);
2124 addButton : function(str, cb)
2128 var b = Roo.apply({}, { html : str } );
2129 b.xns = b.xns || Roo.bootstrap;
2130 b.xtype = b.xtype || 'Button';
2131 if (typeof(b.listeners) == 'undefined') {
2132 b.listeners = { click : cb.createDelegate(this) };
2135 var btn = Roo.factory(b);
2137 btn.onRender(this.el.select('.modal-footer div').first());
2143 setDefaultButton : function(btn)
2145 //this.el.select('.modal-footer').()
2147 resizeTo: function(w,h)
2151 setContentSize : function(w, h)
2155 onButtonClick: function(btn,e)
2158 this.fireEvent('btnclick', btn.name, e);
2160 setTitle: function(str) {
2161 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2167 Roo.apply(Roo.bootstrap.Modal, {
2169 * Button config that displays a single OK button
2178 * Button config that displays Yes and No buttons
2194 * Button config that displays OK and Cancel buttons
2209 * Button config that displays Yes, No and Cancel buttons
2231 * messagebox - can be used as a replace
2235 * @class Roo.MessageBox
2236 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2240 Roo.Msg.alert('Status', 'Changes saved successfully.');
2242 // Prompt for user data:
2243 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2245 // process text value...
2249 // Show a dialog using config options:
2251 title:'Save Changes?',
2252 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2253 buttons: Roo.Msg.YESNOCANCEL,
2260 Roo.bootstrap.MessageBox = function(){
2261 var dlg, opt, mask, waitTimer;
2262 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2263 var buttons, activeTextEl, bwidth;
2267 var handleButton = function(button){
2269 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2273 var handleHide = function(){
2275 dlg.el.removeClass(opt.cls);
2278 // Roo.TaskMgr.stop(waitTimer);
2279 // waitTimer = null;
2284 var updateButtons = function(b){
2287 buttons["ok"].hide();
2288 buttons["cancel"].hide();
2289 buttons["yes"].hide();
2290 buttons["no"].hide();
2291 //dlg.footer.dom.style.display = 'none';
2294 dlg.footer.dom.style.display = '';
2295 for(var k in buttons){
2296 if(typeof buttons[k] != "function"){
2299 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2300 width += buttons[k].el.getWidth()+15;
2310 var handleEsc = function(d, k, e){
2311 if(opt && opt.closable !== false){
2321 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2322 * @return {Roo.BasicDialog} The BasicDialog element
2324 getDialog : function(){
2326 dlg = new Roo.bootstrap.Modal( {
2329 //constraintoviewport:false,
2331 //collapsible : false,
2336 //buttonAlign:"center",
2337 closeClick : function(){
2338 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2341 handleButton("cancel");
2346 dlg.on("hide", handleHide);
2348 //dlg.addKeyListener(27, handleEsc);
2350 this.buttons = buttons;
2351 var bt = this.buttonText;
2352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2357 bodyEl = dlg.body.createChild({
2359 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2360 '<textarea class="roo-mb-textarea"></textarea>' +
2361 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2363 msgEl = bodyEl.dom.firstChild;
2364 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2365 textboxEl.enableDisplayMode();
2366 textboxEl.addKeyListener([10,13], function(){
2367 if(dlg.isVisible() && opt && opt.buttons){
2370 }else if(opt.buttons.yes){
2371 handleButton("yes");
2375 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2376 textareaEl.enableDisplayMode();
2377 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2378 progressEl.enableDisplayMode();
2379 var pf = progressEl.dom.firstChild;
2381 pp = Roo.get(pf.firstChild);
2382 pp.setHeight(pf.offsetHeight);
2390 * Updates the message box body text
2391 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2392 * the XHTML-compliant non-breaking space character '&#160;')
2393 * @return {Roo.MessageBox} This message box
2395 updateText : function(text){
2396 if(!dlg.isVisible() && !opt.width){
2397 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2399 msgEl.innerHTML = text || ' ';
2401 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2402 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2404 Math.min(opt.width || cw , this.maxWidth),
2405 Math.max(opt.minWidth || this.minWidth, bwidth)
2408 activeTextEl.setWidth(w);
2410 if(dlg.isVisible()){
2411 dlg.fixedcenter = false;
2413 // to big, make it scroll. = But as usual stupid IE does not support
2416 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2417 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2418 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2420 bodyEl.dom.style.height = '';
2421 bodyEl.dom.style.overflowY = '';
2424 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2426 bodyEl.dom.style.overflowX = '';
2429 dlg.setContentSize(w, bodyEl.getHeight());
2430 if(dlg.isVisible()){
2431 dlg.fixedcenter = true;
2437 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2438 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2439 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2440 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2441 * @return {Roo.MessageBox} This message box
2443 updateProgress : function(value, text){
2445 this.updateText(text);
2447 if (pp) { // weird bug on my firefox - for some reason this is not defined
2448 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2454 * Returns true if the message box is currently displayed
2455 * @return {Boolean} True if the message box is visible, else false
2457 isVisible : function(){
2458 return dlg && dlg.isVisible();
2462 * Hides the message box if it is displayed
2465 if(this.isVisible()){
2471 * Displays a new message box, or reinitializes an existing message box, based on the config options
2472 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2473 * The following config object properties are supported:
2475 Property Type Description
2476 ---------- --------------- ------------------------------------------------------------------------------------
2477 animEl String/Element An id or Element from which the message box should animate as it opens and
2478 closes (defaults to undefined)
2479 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2480 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2481 closable Boolean False to hide the top-right close button (defaults to true). Note that
2482 progress and wait dialogs will ignore this property and always hide the
2483 close button as they can only be closed programmatically.
2484 cls String A custom CSS class to apply to the message box element
2485 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2486 displayed (defaults to 75)
2487 fn Function A callback function to execute after closing the dialog. The arguments to the
2488 function will be btn (the name of the button that was clicked, if applicable,
2489 e.g. "ok"), and text (the value of the active text field, if applicable).
2490 Progress and wait dialogs will ignore this option since they do not respond to
2491 user actions and can only be closed programmatically, so any required function
2492 should be called by the same code after it closes the dialog.
2493 icon String A CSS class that provides a background image to be used as an icon for
2494 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2495 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2496 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2497 modal Boolean False to allow user interaction with the page while the message box is
2498 displayed (defaults to true)
2499 msg String A string that will replace the existing message box body text (defaults
2500 to the XHTML-compliant non-breaking space character ' ')
2501 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2502 progress Boolean True to display a progress bar (defaults to false)
2503 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2504 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2505 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2506 title String The title text
2507 value String The string value to set into the active textbox element if displayed
2508 wait Boolean True to display a progress bar (defaults to false)
2509 width Number The width of the dialog in pixels
2516 msg: 'Please enter your address:',
2518 buttons: Roo.MessageBox.OKCANCEL,
2521 animEl: 'addAddressBtn'
2524 * @param {Object} config Configuration options
2525 * @return {Roo.MessageBox} This message box
2527 show : function(options)
2530 // this causes nightmares if you show one dialog after another
2531 // especially on callbacks..
2533 if(this.isVisible()){
2536 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2537 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2538 Roo.log("New Dialog Message:" + options.msg )
2539 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2540 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2543 var d = this.getDialog();
2545 d.setTitle(opt.title || " ");
2546 d.close.setDisplayed(opt.closable !== false);
2547 activeTextEl = textboxEl;
2548 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2553 textareaEl.setHeight(typeof opt.multiline == "number" ?
2554 opt.multiline : this.defaultTextHeight);
2555 activeTextEl = textareaEl;
2564 progressEl.setDisplayed(opt.progress === true);
2565 this.updateProgress(0);
2566 activeTextEl.dom.value = opt.value || "";
2568 dlg.setDefaultButton(activeTextEl);
2570 var bs = opt.buttons;
2574 }else if(bs && bs.yes){
2575 db = buttons["yes"];
2577 dlg.setDefaultButton(db);
2579 bwidth = updateButtons(opt.buttons);
2580 this.updateText(opt.msg);
2582 d.el.addClass(opt.cls);
2584 d.proxyDrag = opt.proxyDrag === true;
2585 d.modal = opt.modal !== false;
2586 d.mask = opt.modal !== false ? mask : false;
2588 // force it to the end of the z-index stack so it gets a cursor in FF
2589 document.body.appendChild(dlg.el.dom);
2590 d.animateTarget = null;
2591 d.show(options.animEl);
2597 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2598 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2599 * and closing the message box when the process is complete.
2600 * @param {String} title The title bar text
2601 * @param {String} msg The message box body text
2602 * @return {Roo.MessageBox} This message box
2604 progress : function(title, msg){
2611 minWidth: this.minProgressWidth,
2618 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2619 * If a callback function is passed it will be called after the user clicks the button, and the
2620 * id of the button that was clicked will be passed as the only parameter to the callback
2621 * (could also be the top-right close button).
2622 * @param {String} title The title bar text
2623 * @param {String} msg The message box body text
2624 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2625 * @param {Object} scope (optional) The scope of the callback function
2626 * @return {Roo.MessageBox} This message box
2628 alert : function(title, msg, fn, scope){
2641 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2642 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2643 * You are responsible for closing the message box when the process is complete.
2644 * @param {String} msg The message box body text
2645 * @param {String} title (optional) The title bar text
2646 * @return {Roo.MessageBox} This message box
2648 wait : function(msg, title){
2659 waitTimer = Roo.TaskMgr.start({
2661 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2669 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2670 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2671 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2672 * @param {String} title The title bar text
2673 * @param {String} msg The message box body text
2674 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2675 * @param {Object} scope (optional) The scope of the callback function
2676 * @return {Roo.MessageBox} This message box
2678 confirm : function(title, msg, fn, scope){
2682 buttons: this.YESNO,
2691 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2692 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2693 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2694 * (could also be the top-right close button) and the text that was entered will be passed as the two
2695 * parameters to the callback.
2696 * @param {String} title The title bar text
2697 * @param {String} msg The message box body text
2698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2699 * @param {Object} scope (optional) The scope of the callback function
2700 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2701 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2702 * @return {Roo.MessageBox} This message box
2704 prompt : function(title, msg, fn, scope, multiline){
2708 buttons: this.OKCANCEL,
2713 multiline: multiline,
2720 * Button config that displays a single OK button
2725 * Button config that displays Yes and No buttons
2728 YESNO : {yes:true, no:true},
2730 * Button config that displays OK and Cancel buttons
2733 OKCANCEL : {ok:true, cancel:true},
2735 * Button config that displays Yes, No and Cancel buttons
2738 YESNOCANCEL : {yes:true, no:true, cancel:true},
2741 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2744 defaultTextHeight : 75,
2746 * The maximum width in pixels of the message box (defaults to 600)
2751 * The minimum width in pixels of the message box (defaults to 100)
2756 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2757 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2760 minProgressWidth : 250,
2762 * An object containing the default button text strings that can be overriden for localized language support.
2763 * Supported properties are: ok, cancel, yes and no.
2764 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2777 * Shorthand for {@link Roo.MessageBox}
2779 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2780 Roo.Msg = Roo.Msg || Roo.MessageBox;
2789 * @class Roo.bootstrap.Navbar
2790 * @extends Roo.bootstrap.Component
2791 * Bootstrap Navbar class
2794 * Create a new Navbar
2795 * @param {Object} config The config object
2799 Roo.bootstrap.Navbar = function(config){
2800 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2804 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2813 getAutoCreate : function(){
2816 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2820 initEvents :function ()
2822 //Roo.log(this.el.select('.navbar-toggle',true));
2823 this.el.select('.navbar-toggle',true).on('click', function() {
2824 // Roo.log('click');
2825 this.el.select('.navbar-collapse',true).toggleClass('in');
2833 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2835 var size = this.el.getSize();
2836 this.maskEl.setSize(size.width, size.height);
2837 this.maskEl.enableDisplayMode("block");
2846 getChildContainer : function()
2848 if (this.el.select('.collapse').getCount()) {
2849 return this.el.select('.collapse',true).first();
2882 * @class Roo.bootstrap.NavSimplebar
2883 * @extends Roo.bootstrap.Navbar
2884 * Bootstrap Sidebar class
2886 * @cfg {Boolean} inverse is inverted color
2888 * @cfg {String} type (nav | pills | tabs)
2889 * @cfg {Boolean} arrangement stacked | justified
2890 * @cfg {String} align (left | right) alignment
2892 * @cfg {Boolean} main (true|false) main nav bar? default false
2893 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2895 * @cfg {String} tag (header|footer|nav|div) default is nav
2901 * Create a new Sidebar
2902 * @param {Object} config The config object
2906 Roo.bootstrap.NavSimplebar = function(config){
2907 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2910 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2926 getAutoCreate : function(){
2930 tag : this.tag || 'div',
2943 this.type = this.type || 'nav';
2944 if (['tabs','pills'].indexOf(this.type)!==-1) {
2945 cfg.cn[0].cls += ' nav-' + this.type
2949 if (this.type!=='nav') {
2950 Roo.log('nav type must be nav/tabs/pills')
2952 cfg.cn[0].cls += ' navbar-nav'
2958 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2959 cfg.cn[0].cls += ' nav-' + this.arrangement;
2963 if (this.align === 'right') {
2964 cfg.cn[0].cls += ' navbar-right';
2968 cfg.cls += ' navbar-inverse';
2995 * @class Roo.bootstrap.NavHeaderbar
2996 * @extends Roo.bootstrap.NavSimplebar
2997 * Bootstrap Sidebar class
2999 * @cfg {String} brand what is brand
3000 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
3001 * @cfg {String} brand_href href of the brand
3004 * Create a new Sidebar
3005 * @param {Object} config The config object
3009 Roo.bootstrap.NavHeaderbar = function(config){
3010 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
3013 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
3020 getAutoCreate : function(){
3025 tag: this.nav || 'nav',
3031 cls: 'navbar-header',
3036 cls: 'navbar-toggle',
3037 'data-toggle': 'collapse',
3042 html: 'Toggle navigation'
3062 cls: 'collapse navbar-collapse'
3067 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3069 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3070 cfg.cls += ' navbar-' + this.position;
3072 // tag can override this..
3074 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3077 if (this.brand !== '') {
3080 href: this.brand_href ? this.brand_href : '#',
3081 cls: 'navbar-brand',
3089 cfg.cls += ' main-nav';
3114 * @class Roo.bootstrap.NavSidebar
3115 * @extends Roo.bootstrap.Navbar
3116 * Bootstrap Sidebar class
3119 * Create a new Sidebar
3120 * @param {Object} config The config object
3124 Roo.bootstrap.NavSidebar = function(config){
3125 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3128 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3130 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3132 getAutoCreate : function(){
3137 cls: 'sidebar sidebar-nav'
3159 * @class Roo.bootstrap.NavGroup
3160 * @extends Roo.bootstrap.Component
3161 * Bootstrap NavGroup class
3162 * @cfg {String} align left | right
3163 * @cfg {Boolean} inverse false | true
3164 * @cfg {String} type (nav|pills|tab) default nav
3165 * @cfg {String} navId - reference Id for navbar.
3169 * Create a new nav group
3170 * @param {Object} config The config object
3173 Roo.bootstrap.NavGroup = function(config){
3174 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3176 Roo.bootstrap.NavGroup.register(this);
3180 * Fires when the active item changes
3181 * @param {Roo.bootstrap.NavGroup} this
3182 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3183 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3190 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3201 getAutoCreate : function()
3203 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3210 if (['tabs','pills'].indexOf(this.type)!==-1) {
3211 cfg.cls += ' nav-' + this.type
3213 if (this.type!=='nav') {
3214 Roo.log('nav type must be nav/tabs/pills')
3216 cfg.cls += ' navbar-nav'
3219 if (this.parent().sidebar) {
3222 cls: 'dashboard-menu sidebar-menu'
3228 if (this.form === true) {
3234 if (this.align === 'right') {
3235 cfg.cls += ' navbar-right';
3237 cfg.cls += ' navbar-left';
3241 if (this.align === 'right') {
3242 cfg.cls += ' navbar-right';
3246 cfg.cls += ' navbar-inverse';
3254 setActiveItem : function(item)
3257 Roo.each(this.navItems, function(v){
3262 v.setActive(false, true);
3269 item.setActive(true, true);
3270 this.fireEvent('changed', this, item, prev);
3275 addItem : function(cfg)
3277 var cn = new Roo.bootstrap.NavItem(cfg);
3279 cn.parentId = this.id;
3280 cn.onRender(this.el, null);
3284 register : function(item)
3286 this.navItems.push( item);
3287 item.navId = this.navId;
3290 getNavItem: function(tabId)
3293 Roo.each(this.navItems, function(e) {
3294 if (e.tabId == tabId) {
3310 Roo.apply(Roo.bootstrap.NavGroup, {
3314 register : function(navgrp)
3316 this.groups[navgrp.navId] = navgrp;
3319 get: function(navId) {
3320 return this.groups[navId];
3335 * @class Roo.bootstrap.NavItem
3336 * @extends Roo.bootstrap.Component
3337 * Bootstrap Navbar.NavItem class
3338 * @cfg {String} href link to
3339 * @cfg {String} html content of button
3340 * @cfg {String} badge text inside badge
3341 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3342 * @cfg {String} glyphicon name of glyphicon
3343 * @cfg {String} icon name of font awesome icon
3344 * @cfg {Boolean} active Is item active
3345 * @cfg {Boolean} disabled Is item disabled
3347 * @cfg {Boolean} preventDefault (true | false) default false
3348 * @cfg {String} tabId the tab that this item activates.
3349 * @cfg {String} tagtype (a|span) render as a href or span?
3352 * Create a new Navbar Item
3353 * @param {Object} config The config object
3355 Roo.bootstrap.NavItem = function(config){
3356 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3361 * The raw click event for the entire grid.
3362 * @param {Roo.EventObject} e
3367 * Fires when the active item active state changes
3368 * @param {Roo.bootstrap.NavItem} this
3369 * @param {boolean} state the new state
3377 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3385 preventDefault : false,
3390 getAutoCreate : function(){
3398 href : this.href || "#",
3399 html: this.html || ''
3405 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3408 // glyphicon and icon go before content..
3409 if (this.glyphicon || this.icon) {
3411 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3413 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3421 cfg.cn[0].html += " <span class='caret'></span>";
3425 if (this.badge !== '') {
3427 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3429 if (this.disabled) {
3430 cfg.cls += ' disabled';
3436 initEvents: function() {
3437 // Roo.log('init events?');
3438 // Roo.log(this.el.dom);
3439 if (typeof (this.menu) != 'undefined') {
3440 this.menu.parentType = this.xtype;
3441 this.menu.triggerEl = this.el;
3442 this.addxtype(Roo.apply({}, this.menu));
3446 this.el.select('a',true).on('click', this.onClick, this);
3447 // at this point parent should be available..
3448 this.parent().register(this);
3451 onClick : function(e)
3454 if(this.preventDefault){
3457 if (this.disabled) {
3460 Roo.log("fire event clicked");
3461 if(this.fireEvent('click', this, e) === false){
3465 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3466 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3467 this.parent().setActiveItem(this);
3475 isActive: function () {
3478 setActive : function(state, fire)
3480 this.active = state;
3482 this.el.removeClass('active');
3483 } else if (!this.el.hasClass('active')) {
3484 this.el.addClass('active');
3487 this.fireEvent('changed', this, state);
3492 // this should not be here...
3493 setDisabled : function(state)
3495 this.disabled = state;
3497 this.el.removeClass('disabled');
3498 } else if (!this.el.hasClass('disabled')) {
3499 this.el.addClass('disabled');
3512 * <span> icon </span>
3513 * <span> text </span>
3514 * <span>badge </span>
3518 * @class Roo.bootstrap.NavSidebarItem
3519 * @extends Roo.bootstrap.NavItem
3520 * Bootstrap Navbar.NavSidebarItem class
3522 * Create a new Navbar Button
3523 * @param {Object} config The config object
3525 Roo.bootstrap.NavSidebarItem = function(config){
3526 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3531 * The raw click event for the entire grid.
3532 * @param {Roo.EventObject} e
3537 * Fires when the active item active state changes
3538 * @param {Roo.bootstrap.NavSidebarItem} this
3539 * @param {boolean} state the new state
3547 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3550 getAutoCreate : function(){
3555 href : this.href || '#',
3567 html : this.html || ''
3572 cfg.cls += ' active';
3576 if (this.glyphicon || this.icon) {
3577 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3578 a.cn.push({ tag : 'i', cls : c }) ;
3583 if (this.badge !== '') {
3584 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3588 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3589 a.cls += 'dropdown-toggle treeview' ;
3613 * @class Roo.bootstrap.Row
3614 * @extends Roo.bootstrap.Component
3615 * Bootstrap Row class (contains columns...)
3619 * @param {Object} config The config object
3622 Roo.bootstrap.Row = function(config){
3623 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3626 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3628 getAutoCreate : function(){
3647 * @class Roo.bootstrap.Element
3648 * @extends Roo.bootstrap.Component
3649 * Bootstrap Element class
3650 * @cfg {String} html contents of the element
3651 * @cfg {String} tag tag of the element
3652 * @cfg {String} cls class of the element
3655 * Create a new Element
3656 * @param {Object} config The config object
3659 Roo.bootstrap.Element = function(config){
3660 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3663 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3670 getAutoCreate : function(){
3695 * @class Roo.bootstrap.Pagination
3696 * @extends Roo.bootstrap.Component
3697 * Bootstrap Pagination class
3698 * @cfg {String} size xs | sm | md | lg
3699 * @cfg {Boolean} inverse false | true
3702 * Create a new Pagination
3703 * @param {Object} config The config object
3706 Roo.bootstrap.Pagination = function(config){
3707 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3710 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3716 getAutoCreate : function(){
3722 cfg.cls += ' inverse';
3728 cfg.cls += " " + this.cls;
3746 * @class Roo.bootstrap.PaginationItem
3747 * @extends Roo.bootstrap.Component
3748 * Bootstrap PaginationItem class
3749 * @cfg {String} html text
3750 * @cfg {String} href the link
3751 * @cfg {Boolean} preventDefault (true | false) default true
3752 * @cfg {Boolean} active (true | false) default false
3756 * Create a new PaginationItem
3757 * @param {Object} config The config object
3761 Roo.bootstrap.PaginationItem = function(config){
3762 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3767 * The raw click event for the entire grid.
3768 * @param {Roo.EventObject} e
3774 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3778 preventDefault: true,
3782 getAutoCreate : function(){
3788 href : this.href ? this.href : '#',
3789 html : this.html ? this.html : ''
3799 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3805 initEvents: function() {
3807 this.el.on('click', this.onClick, this);
3810 onClick : function(e)
3812 Roo.log('PaginationItem on click ');
3813 if(this.preventDefault){
3817 this.fireEvent('click', this, e);
3833 * @class Roo.bootstrap.Slider
3834 * @extends Roo.bootstrap.Component
3835 * Bootstrap Slider class
3838 * Create a new Slider
3839 * @param {Object} config The config object
3842 Roo.bootstrap.Slider = function(config){
3843 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3846 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3848 getAutoCreate : function(){
3852 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3856 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3868 * Ext JS Library 1.1.1
3869 * Copyright(c) 2006-2007, Ext JS, LLC.
3871 * Originally Released Under LGPL - original licence link has changed is not relivant.
3874 * <script type="text/javascript">
3879 * @class Roo.grid.ColumnModel
3880 * @extends Roo.util.Observable
3881 * This is the default implementation of a ColumnModel used by the Grid. It defines
3882 * the columns in the grid.
3885 var colModel = new Roo.grid.ColumnModel([
3886 {header: "Ticker", width: 60, sortable: true, locked: true},
3887 {header: "Company Name", width: 150, sortable: true},
3888 {header: "Market Cap.", width: 100, sortable: true},
3889 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3890 {header: "Employees", width: 100, sortable: true, resizable: false}
3895 * The config options listed for this class are options which may appear in each
3896 * individual column definition.
3897 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3899 * @param {Object} config An Array of column config objects. See this class's
3900 * config objects for details.
3902 Roo.grid.ColumnModel = function(config){
3904 * The config passed into the constructor
3906 this.config = config;
3909 // if no id, create one
3910 // if the column does not have a dataIndex mapping,
3911 // map it to the order it is in the config
3912 for(var i = 0, len = config.length; i < len; i++){
3914 if(typeof c.dataIndex == "undefined"){
3917 if(typeof c.renderer == "string"){
3918 c.renderer = Roo.util.Format[c.renderer];
3920 if(typeof c.id == "undefined"){
3923 if(c.editor && c.editor.xtype){
3924 c.editor = Roo.factory(c.editor, Roo.grid);
3926 if(c.editor && c.editor.isFormField){
3927 c.editor = new Roo.grid.GridEditor(c.editor);
3929 this.lookup[c.id] = c;
3933 * The width of columns which have no width specified (defaults to 100)
3936 this.defaultWidth = 100;
3939 * Default sortable of columns which have no sortable specified (defaults to false)
3942 this.defaultSortable = false;
3946 * @event widthchange
3947 * Fires when the width of a column changes.
3948 * @param {ColumnModel} this
3949 * @param {Number} columnIndex The column index
3950 * @param {Number} newWidth The new width
3952 "widthchange": true,
3954 * @event headerchange
3955 * Fires when the text of a header changes.
3956 * @param {ColumnModel} this
3957 * @param {Number} columnIndex The column index
3958 * @param {Number} newText The new header text
3960 "headerchange": true,
3962 * @event hiddenchange
3963 * Fires when a column is hidden or "unhidden".
3964 * @param {ColumnModel} this
3965 * @param {Number} columnIndex The column index
3966 * @param {Boolean} hidden true if hidden, false otherwise
3968 "hiddenchange": true,
3970 * @event columnmoved
3971 * Fires when a column is moved.
3972 * @param {ColumnModel} this
3973 * @param {Number} oldIndex
3974 * @param {Number} newIndex
3976 "columnmoved" : true,
3978 * @event columlockchange
3979 * Fires when a column's locked state is changed
3980 * @param {ColumnModel} this
3981 * @param {Number} colIndex
3982 * @param {Boolean} locked true if locked
3984 "columnlockchange" : true
3986 Roo.grid.ColumnModel.superclass.constructor.call(this);
3988 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3990 * @cfg {String} header The header text to display in the Grid view.
3993 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3994 * {@link Roo.data.Record} definition from which to draw the column's value. If not
3995 * specified, the column's index is used as an index into the Record's data Array.
3998 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
3999 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4002 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4003 * Defaults to the value of the {@link #defaultSortable} property.
4004 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4007 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4010 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4013 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4016 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4019 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4020 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4021 * default renderer uses the raw data value.
4024 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4027 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4031 * Returns the id of the column at the specified index.
4032 * @param {Number} index The column index
4033 * @return {String} the id
4035 getColumnId : function(index){
4036 return this.config[index].id;
4040 * Returns the column for a specified id.
4041 * @param {String} id The column id
4042 * @return {Object} the column
4044 getColumnById : function(id){
4045 return this.lookup[id];
4050 * Returns the column for a specified dataIndex.
4051 * @param {String} dataIndex The column dataIndex
4052 * @return {Object|Boolean} the column or false if not found
4054 getColumnByDataIndex: function(dataIndex){
4055 var index = this.findColumnIndex(dataIndex);
4056 return index > -1 ? this.config[index] : false;
4060 * Returns the index for a specified column id.
4061 * @param {String} id The column id
4062 * @return {Number} the index, or -1 if not found
4064 getIndexById : function(id){
4065 for(var i = 0, len = this.config.length; i < len; i++){
4066 if(this.config[i].id == id){
4074 * Returns the index for a specified column dataIndex.
4075 * @param {String} dataIndex The column dataIndex
4076 * @return {Number} the index, or -1 if not found
4079 findColumnIndex : function(dataIndex){
4080 for(var i = 0, len = this.config.length; i < len; i++){
4081 if(this.config[i].dataIndex == dataIndex){
4089 moveColumn : function(oldIndex, newIndex){
4090 var c = this.config[oldIndex];
4091 this.config.splice(oldIndex, 1);
4092 this.config.splice(newIndex, 0, c);
4093 this.dataMap = null;
4094 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4097 isLocked : function(colIndex){
4098 return this.config[colIndex].locked === true;
4101 setLocked : function(colIndex, value, suppressEvent){
4102 if(this.isLocked(colIndex) == value){
4105 this.config[colIndex].locked = value;
4107 this.fireEvent("columnlockchange", this, colIndex, value);
4111 getTotalLockedWidth : function(){
4113 for(var i = 0; i < this.config.length; i++){
4114 if(this.isLocked(i) && !this.isHidden(i)){
4115 this.totalWidth += this.getColumnWidth(i);
4121 getLockedCount : function(){
4122 for(var i = 0, len = this.config.length; i < len; i++){
4123 if(!this.isLocked(i)){
4130 * Returns the number of columns.
4133 getColumnCount : function(visibleOnly){
4134 if(visibleOnly === true){
4136 for(var i = 0, len = this.config.length; i < len; i++){
4137 if(!this.isHidden(i)){
4143 return this.config.length;
4147 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4148 * @param {Function} fn
4149 * @param {Object} scope (optional)
4150 * @return {Array} result
4152 getColumnsBy : function(fn, scope){
4154 for(var i = 0, len = this.config.length; i < len; i++){
4155 var c = this.config[i];
4156 if(fn.call(scope||this, c, i) === true){
4164 * Returns true if the specified column is sortable.
4165 * @param {Number} col The column index
4168 isSortable : function(col){
4169 if(typeof this.config[col].sortable == "undefined"){
4170 return this.defaultSortable;
4172 return this.config[col].sortable;
4176 * Returns the rendering (formatting) function defined for the column.
4177 * @param {Number} col The column index.
4178 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4180 getRenderer : function(col){
4181 if(!this.config[col].renderer){
4182 return Roo.grid.ColumnModel.defaultRenderer;
4184 return this.config[col].renderer;
4188 * Sets the rendering (formatting) function for a column.
4189 * @param {Number} col The column index
4190 * @param {Function} fn The function to use to process the cell's raw data
4191 * to return HTML markup for the grid view. The render function is called with
4192 * the following parameters:<ul>
4193 * <li>Data value.</li>
4194 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4195 * <li>css A CSS style string to apply to the table cell.</li>
4196 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4197 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4198 * <li>Row index</li>
4199 * <li>Column index</li>
4200 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4202 setRenderer : function(col, fn){
4203 this.config[col].renderer = fn;
4207 * Returns the width for the specified column.
4208 * @param {Number} col The column index
4211 getColumnWidth : function(col){
4212 return this.config[col].width * 1 || this.defaultWidth;
4216 * Sets the width for a column.
4217 * @param {Number} col The column index
4218 * @param {Number} width The new width
4220 setColumnWidth : function(col, width, suppressEvent){
4221 this.config[col].width = width;
4222 this.totalWidth = null;
4224 this.fireEvent("widthchange", this, col, width);
4229 * Returns the total width of all columns.
4230 * @param {Boolean} includeHidden True to include hidden column widths
4233 getTotalWidth : function(includeHidden){
4234 if(!this.totalWidth){
4235 this.totalWidth = 0;
4236 for(var i = 0, len = this.config.length; i < len; i++){
4237 if(includeHidden || !this.isHidden(i)){
4238 this.totalWidth += this.getColumnWidth(i);
4242 return this.totalWidth;
4246 * Returns the header for the specified column.
4247 * @param {Number} col The column index
4250 getColumnHeader : function(col){
4251 return this.config[col].header;
4255 * Sets the header for a column.
4256 * @param {Number} col The column index
4257 * @param {String} header The new header
4259 setColumnHeader : function(col, header){
4260 this.config[col].header = header;
4261 this.fireEvent("headerchange", this, col, header);
4265 * Returns the tooltip for the specified column.
4266 * @param {Number} col The column index
4269 getColumnTooltip : function(col){
4270 return this.config[col].tooltip;
4273 * Sets the tooltip for a column.
4274 * @param {Number} col The column index
4275 * @param {String} tooltip The new tooltip
4277 setColumnTooltip : function(col, tooltip){
4278 this.config[col].tooltip = tooltip;
4282 * Returns the dataIndex for the specified column.
4283 * @param {Number} col The column index
4286 getDataIndex : function(col){
4287 return this.config[col].dataIndex;
4291 * Sets the dataIndex for a column.
4292 * @param {Number} col The column index
4293 * @param {Number} dataIndex The new dataIndex
4295 setDataIndex : function(col, dataIndex){
4296 this.config[col].dataIndex = dataIndex;
4302 * Returns true if the cell is editable.
4303 * @param {Number} colIndex The column index
4304 * @param {Number} rowIndex The row index
4307 isCellEditable : function(colIndex, rowIndex){
4308 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4312 * Returns the editor defined for the cell/column.
4313 * return false or null to disable editing.
4314 * @param {Number} colIndex The column index
4315 * @param {Number} rowIndex The row index
4318 getCellEditor : function(colIndex, rowIndex){
4319 return this.config[colIndex].editor;
4323 * Sets if a column is editable.
4324 * @param {Number} col The column index
4325 * @param {Boolean} editable True if the column is editable
4327 setEditable : function(col, editable){
4328 this.config[col].editable = editable;
4333 * Returns true if the column is hidden.
4334 * @param {Number} colIndex The column index
4337 isHidden : function(colIndex){
4338 return this.config[colIndex].hidden;
4343 * Returns true if the column width cannot be changed
4345 isFixed : function(colIndex){
4346 return this.config[colIndex].fixed;
4350 * Returns true if the column can be resized
4353 isResizable : function(colIndex){
4354 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4357 * Sets if a column is hidden.
4358 * @param {Number} colIndex The column index
4359 * @param {Boolean} hidden True if the column is hidden
4361 setHidden : function(colIndex, hidden){
4362 this.config[colIndex].hidden = hidden;
4363 this.totalWidth = null;
4364 this.fireEvent("hiddenchange", this, colIndex, hidden);
4368 * Sets the editor for a column.
4369 * @param {Number} col The column index
4370 * @param {Object} editor The editor object
4372 setEditor : function(col, editor){
4373 this.config[col].editor = editor;
4377 Roo.grid.ColumnModel.defaultRenderer = function(value){
4378 if(typeof value == "string" && value.length < 1){
4384 // Alias for backwards compatibility
4385 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4388 * Ext JS Library 1.1.1
4389 * Copyright(c) 2006-2007, Ext JS, LLC.
4391 * Originally Released Under LGPL - original licence link has changed is not relivant.
4394 * <script type="text/javascript">
4398 * @class Roo.LoadMask
4399 * A simple utility class for generically masking elements while loading data. If the element being masked has
4400 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4401 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4402 * element's UpdateManager load indicator and will be destroyed after the initial load.
4404 * Create a new LoadMask
4405 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4406 * @param {Object} config The config object
4408 Roo.LoadMask = function(el, config){
4409 this.el = Roo.get(el);
4410 Roo.apply(this, config);
4412 this.store.on('beforeload', this.onBeforeLoad, this);
4413 this.store.on('load', this.onLoad, this);
4414 this.store.on('loadexception', this.onLoadException, this);
4415 this.removeMask = false;
4417 var um = this.el.getUpdateManager();
4418 um.showLoadIndicator = false; // disable the default indicator
4419 um.on('beforeupdate', this.onBeforeLoad, this);
4420 um.on('update', this.onLoad, this);
4421 um.on('failure', this.onLoad, this);
4422 this.removeMask = true;
4426 Roo.LoadMask.prototype = {
4428 * @cfg {Boolean} removeMask
4429 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4430 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4434 * The text to display in a centered loading message box (defaults to 'Loading...')
4438 * @cfg {String} msgCls
4439 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4441 msgCls : 'x-mask-loading',
4444 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4450 * Disables the mask to prevent it from being displayed
4452 disable : function(){
4453 this.disabled = true;
4457 * Enables the mask so that it can be displayed
4459 enable : function(){
4460 this.disabled = false;
4463 onLoadException : function()
4467 if (typeof(arguments[3]) != 'undefined') {
4468 Roo.MessageBox.alert("Error loading",arguments[3]);
4472 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4473 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4482 this.el.unmask(this.removeMask);
4487 this.el.unmask(this.removeMask);
4491 onBeforeLoad : function(){
4493 this.el.mask(this.msg, this.msgCls);
4498 destroy : function(){
4500 this.store.un('beforeload', this.onBeforeLoad, this);
4501 this.store.un('load', this.onLoad, this);
4502 this.store.un('loadexception', this.onLoadException, this);
4504 var um = this.el.getUpdateManager();
4505 um.un('beforeupdate', this.onBeforeLoad, this);
4506 um.un('update', this.onLoad, this);
4507 um.un('failure', this.onLoad, this);
4518 * @class Roo.bootstrap.Table
4519 * @extends Roo.bootstrap.Component
4520 * Bootstrap Table class
4521 * @cfg {String} cls table class
4522 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4523 * @cfg {String} bgcolor Specifies the background color for a table
4524 * @cfg {Number} border Specifies whether the table cells should have borders or not
4525 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4526 * @cfg {Number} cellspacing Specifies the space between cells
4527 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4528 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4529 * @cfg {String} sortable Specifies that the table should be sortable
4530 * @cfg {String} summary Specifies a summary of the content of a table
4531 * @cfg {Number} width Specifies the width of a table
4532 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4534 * @cfg {boolean} striped Should the rows be alternative striped
4535 * @cfg {boolean} bordered Add borders to the table
4536 * @cfg {boolean} hover Add hover highlighting
4537 * @cfg {boolean} condensed Format condensed
4538 * @cfg {boolean} responsive Format condensed
4539 * @cfg {Boolean} loadMask (true|false) default false
4540 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4541 * @cfg {Boolean} thead (true|false) generate thead, default true
4542 * @cfg {Boolean} RowSelection (true|false) default false
4543 * @cfg {Boolean} CellSelection (true|false) default false
4545 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4549 * Create a new Table
4550 * @param {Object} config The config object
4553 Roo.bootstrap.Table = function(config){
4554 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4557 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4558 this.sm = this.selModel;
4559 this.sm.xmodule = this.xmodule || false;
4561 if (this.cm && typeof(this.cm.config) == 'undefined') {
4562 this.colModel = new Roo.grid.ColumnModel(this.cm);
4563 this.cm = this.colModel;
4564 this.cm.xmodule = this.xmodule || false;
4567 this.store= Roo.factory(this.store, Roo.data);
4568 this.ds = this.store;
4569 this.ds.xmodule = this.xmodule || false;
4572 if (this.footer && this.store) {
4573 this.footer.dataSource = this.ds;
4574 this.footer = Roo.factory(this.footer);
4581 * Fires when a cell is clicked
4582 * @param {Roo.bootstrap.Table} this
4583 * @param {Roo.Element} el
4584 * @param {Number} rowIndex
4585 * @param {Number} columnIndex
4586 * @param {Roo.EventObject} e
4590 * @event celldblclick
4591 * Fires when a cell is double clicked
4592 * @param {Roo.bootstrap.Table} this
4593 * @param {Roo.Element} el
4594 * @param {Number} rowIndex
4595 * @param {Number} columnIndex
4596 * @param {Roo.EventObject} e
4598 "celldblclick" : true,
4601 * Fires when a row is clicked
4602 * @param {Roo.bootstrap.Table} this
4603 * @param {Roo.Element} el
4604 * @param {Number} rowIndex
4605 * @param {Roo.EventObject} e
4609 * @event rowdblclick
4610 * Fires when a row is double clicked
4611 * @param {Roo.bootstrap.Table} this
4612 * @param {Roo.Element} el
4613 * @param {Number} rowIndex
4614 * @param {Roo.EventObject} e
4616 "rowdblclick" : true,
4619 * Fires when a row is rendered, so you can change add a style to it.
4620 * @param {Roo.bootstrap.Table} this
4621 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4628 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4652 RowSelection : false,
4653 CellSelection : false,
4657 getAutoCreate : function(){
4658 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4667 cfg.cls += ' table-striped';
4671 cfg.cls += ' table-hover';
4673 if (this.bordered) {
4674 cfg.cls += ' table-bordered';
4676 if (this.condensed) {
4677 cfg.cls += ' table-condensed';
4679 if (this.responsive) {
4680 cfg.cls += ' table-responsive';
4684 cfg.cls+= ' ' +this.cls;
4687 // this lot should be simplifed...
4690 cfg.align=this.align;
4693 cfg.bgcolor=this.bgcolor;
4696 cfg.border=this.border;
4698 if (this.cellpadding) {
4699 cfg.cellpadding=this.cellpadding;
4701 if (this.cellspacing) {
4702 cfg.cellspacing=this.cellspacing;
4705 cfg.frame=this.frame;
4708 cfg.rules=this.rules;
4710 if (this.sortable) {
4711 cfg.sortable=this.sortable;
4714 cfg.summary=this.summary;
4717 cfg.width=this.width;
4720 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4723 if(this.store || this.cm){
4725 cfg.cn.push(this.renderHeader());
4728 cfg.cn.push(this.renderBody());
4731 cfg.cn.push(this.renderFooter());
4734 cfg.cls+= ' TableGrid';
4737 return { cn : [ cfg ] };
4740 initEvents : function()
4742 if(!this.store || !this.cm){
4746 Roo.log('initEvents with ds!!!!');
4750 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4751 e.on('click', _this.sort, _this);
4754 this.el.on("click", this.onClick, this);
4755 this.el.on("dblclick", this.onDblClick, this);
4757 this.parent().el.setStyle('position', 'relative');
4759 this.footer.parentId = this.id;
4760 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4763 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4765 this.store.on('load', this.onLoad, this);
4766 this.store.on('beforeload', this.onBeforeLoad, this);
4770 onClick : function(e, el)
4772 var cell = Roo.get(el);
4773 var row = cell.findParent('tr', false, true);
4774 var cellIndex = cell.dom.cellIndex;
4775 var rowIndex = row.dom.rowIndex;
4777 if(this.CellSelection){
4778 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4781 if(this.RowSelection){
4782 this.fireEvent('rowclick', this, row, rowIndex, e);
4788 onDblClick : function(e,el)
4790 var cell = Roo.get(el);;
4791 var row = cell.findParent('tr', false, true);
4792 var cellIndex = cell.dom.cellIndex;
4793 var rowIndex = row.dom.rowIndex;
4795 if(this.CellSelection){
4796 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4799 if(this.RowSelection){
4800 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4804 sort : function(e,el)
4806 var col = Roo.get(el)
4808 if(!col.hasClass('sortable')){
4812 var sort = col.attr('sort');
4815 if(col.hasClass('glyphicon-arrow-up')){
4819 this.store.sortInfo = {field : sort, direction : dir};
4822 Roo.log("calling footer first");
4823 this.footer.onClick('first');
4826 this.store.load({ params : { start : 0 } });
4830 renderHeader : function()
4839 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4841 var config = cm.config[i];
4843 if(typeof(config.hidden) != 'undefined' && config.hidden){
4850 html: cm.getColumnHeader(i)
4853 if(typeof(config.dataIndex) != 'undefined'){
4854 c.sort = config.dataIndex;
4857 if(typeof(config.sortable) != 'undefined' && config.sortable){
4861 // if(typeof(config.align) != 'undefined' && config.align.length){
4862 // c.style += ' text-align:' + config.align + ';';
4865 if(typeof(config.width) != 'undefined'){
4866 c.style += ' width:' + config.width + 'px;';
4875 renderBody : function()
4885 colspan : this.cm.getColumnCount()
4895 renderFooter : function()
4905 colspan : this.cm.getColumnCount()
4917 Roo.log('ds onload');
4923 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4924 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4926 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4927 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4930 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4931 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4935 var tbody = this.el.select('tbody', true).first();
4939 if(this.store.getCount() > 0){
4940 this.store.data.each(function(d,rowIndex){
4946 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4947 var config = cm.config[i];
4949 if(typeof(config.hidden) != 'undefined' && config.hidden){
4953 var renderer = cm.getRenderer(i);
4957 if(typeof(renderer) !== 'undefined'){
4958 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4961 if(typeof(value) === 'object'){
4970 rowIndex : rowIndex,
4975 _this.fireEvent('rowclass', this, rowcfg);
4980 cls : rowcfg.rowClass,
4982 html: (typeof(value) === 'object') ? '' : value
4985 if(typeof(config.align) != 'undefined' && config.align.length){
4986 td.style += ' text-align:' + config.align + ';';
4989 if(typeof(config.width) != 'undefined'){
4990 td.style += ' width:' + config.width + 'px;';
4998 tbody.createChild(row);
5006 Roo.each(renders, function(r){
5007 _this.renderColumn(r);
5011 //if(this.loadMask){
5012 // this.maskEl.hide();
5016 onBeforeLoad : function()
5018 //Roo.log('ds onBeforeLoad');
5022 //if(this.loadMask){
5023 // this.maskEl.show();
5029 this.el.select('tbody', true).first().dom.innerHTML = '';
5032 getSelectionModel : function(){
5034 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5036 return this.selModel;
5039 renderColumn : function(r)
5042 r.cfg.render(Roo.get(r.id));
5045 Roo.each(r.cfg.cn, function(c){
5050 _this.renderColumn(child);
5067 * @class Roo.bootstrap.TableCell
5068 * @extends Roo.bootstrap.Component
5069 * Bootstrap TableCell class
5070 * @cfg {String} html cell contain text
5071 * @cfg {String} cls cell class
5072 * @cfg {String} tag cell tag (td|th) default td
5073 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5074 * @cfg {String} align Aligns the content in a cell
5075 * @cfg {String} axis Categorizes cells
5076 * @cfg {String} bgcolor Specifies the background color of a cell
5077 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5078 * @cfg {Number} colspan Specifies the number of columns a cell should span
5079 * @cfg {String} headers Specifies one or more header cells a cell is related to
5080 * @cfg {Number} height Sets the height of a cell
5081 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5082 * @cfg {Number} rowspan Sets the number of rows a cell should span
5083 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5084 * @cfg {String} valign Vertical aligns the content in a cell
5085 * @cfg {Number} width Specifies the width of a cell
5088 * Create a new TableCell
5089 * @param {Object} config The config object
5092 Roo.bootstrap.TableCell = function(config){
5093 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5096 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5116 getAutoCreate : function(){
5117 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5137 cfg.align=this.align
5143 cfg.bgcolor=this.bgcolor
5146 cfg.charoff=this.charoff
5149 cfg.colspan=this.colspan
5152 cfg.headers=this.headers
5155 cfg.height=this.height
5158 cfg.nowrap=this.nowrap
5161 cfg.rowspan=this.rowspan
5164 cfg.scope=this.scope
5167 cfg.valign=this.valign
5170 cfg.width=this.width
5189 * @class Roo.bootstrap.TableRow
5190 * @extends Roo.bootstrap.Component
5191 * Bootstrap TableRow class
5192 * @cfg {String} cls row class
5193 * @cfg {String} align Aligns the content in a table row
5194 * @cfg {String} bgcolor Specifies a background color for a table row
5195 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5196 * @cfg {String} valign Vertical aligns the content in a table row
5199 * Create a new TableRow
5200 * @param {Object} config The config object
5203 Roo.bootstrap.TableRow = function(config){
5204 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5207 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5215 getAutoCreate : function(){
5216 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5226 cfg.align = this.align;
5229 cfg.bgcolor = this.bgcolor;
5232 cfg.charoff = this.charoff;
5235 cfg.valign = this.valign;
5253 * @class Roo.bootstrap.TableBody
5254 * @extends Roo.bootstrap.Component
5255 * Bootstrap TableBody class
5256 * @cfg {String} cls element class
5257 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5258 * @cfg {String} align Aligns the content inside the element
5259 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5260 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5263 * Create a new TableBody
5264 * @param {Object} config The config object
5267 Roo.bootstrap.TableBody = function(config){
5268 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5271 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5279 getAutoCreate : function(){
5280 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5294 cfg.align = this.align;
5297 cfg.charoff = this.charoff;
5300 cfg.valign = this.valign;
5307 // initEvents : function()
5314 // this.store = Roo.factory(this.store, Roo.data);
5315 // this.store.on('load', this.onLoad, this);
5317 // this.store.load();
5321 // onLoad: function ()
5323 // this.fireEvent('load', this);
5333 * Ext JS Library 1.1.1
5334 * Copyright(c) 2006-2007, Ext JS, LLC.
5336 * Originally Released Under LGPL - original licence link has changed is not relivant.
5339 * <script type="text/javascript">
5342 // as we use this in bootstrap.
5343 Roo.namespace('Roo.form');
5345 * @class Roo.form.Action
5346 * Internal Class used to handle form actions
5348 * @param {Roo.form.BasicForm} el The form element or its id
5349 * @param {Object} config Configuration options
5354 // define the action interface
5355 Roo.form.Action = function(form, options){
5357 this.options = options || {};
5360 * Client Validation Failed
5363 Roo.form.Action.CLIENT_INVALID = 'client';
5365 * Server Validation Failed
5368 Roo.form.Action.SERVER_INVALID = 'server';
5370 * Connect to Server Failed
5373 Roo.form.Action.CONNECT_FAILURE = 'connect';
5375 * Reading Data from Server Failed
5378 Roo.form.Action.LOAD_FAILURE = 'load';
5380 Roo.form.Action.prototype = {
5382 failureType : undefined,
5383 response : undefined,
5387 run : function(options){
5392 success : function(response){
5397 handleResponse : function(response){
5401 // default connection failure
5402 failure : function(response){
5404 this.response = response;
5405 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5406 this.form.afterAction(this, false);
5409 processResponse : function(response){
5410 this.response = response;
5411 if(!response.responseText){
5414 this.result = this.handleResponse(response);
5418 // utility functions used internally
5419 getUrl : function(appendParams){
5420 var url = this.options.url || this.form.url || this.form.el.dom.action;
5422 var p = this.getParams();
5424 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5430 getMethod : function(){
5431 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5434 getParams : function(){
5435 var bp = this.form.baseParams;
5436 var p = this.options.params;
5438 if(typeof p == "object"){
5439 p = Roo.urlEncode(Roo.applyIf(p, bp));
5440 }else if(typeof p == 'string' && bp){
5441 p += '&' + Roo.urlEncode(bp);
5444 p = Roo.urlEncode(bp);
5449 createCallback : function(){
5451 success: this.success,
5452 failure: this.failure,
5454 timeout: (this.form.timeout*1000),
5455 upload: this.form.fileUpload ? this.success : undefined
5460 Roo.form.Action.Submit = function(form, options){
5461 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5464 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5467 haveProgress : false,
5468 uploadComplete : false,
5470 // uploadProgress indicator.
5471 uploadProgress : function()
5473 if (!this.form.progressUrl) {
5477 if (!this.haveProgress) {
5478 Roo.MessageBox.progress("Uploading", "Uploading");
5480 if (this.uploadComplete) {
5481 Roo.MessageBox.hide();
5485 this.haveProgress = true;
5487 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5489 var c = new Roo.data.Connection();
5491 url : this.form.progressUrl,
5496 success : function(req){
5497 //console.log(data);
5501 rdata = Roo.decode(req.responseText)
5503 Roo.log("Invalid data from server..");
5507 if (!rdata || !rdata.success) {
5509 Roo.MessageBox.alert(Roo.encode(rdata));
5512 var data = rdata.data;
5514 if (this.uploadComplete) {
5515 Roo.MessageBox.hide();
5520 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5521 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5524 this.uploadProgress.defer(2000,this);
5527 failure: function(data) {
5528 Roo.log('progress url failed ');
5539 // run get Values on the form, so it syncs any secondary forms.
5540 this.form.getValues();
5542 var o = this.options;
5543 var method = this.getMethod();
5544 var isPost = method == 'POST';
5545 if(o.clientValidation === false || this.form.isValid()){
5547 if (this.form.progressUrl) {
5548 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5549 (new Date() * 1) + '' + Math.random());
5554 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5555 form:this.form.el.dom,
5556 url:this.getUrl(!isPost),
5558 params:isPost ? this.getParams() : null,
5559 isUpload: this.form.fileUpload
5562 this.uploadProgress();
5564 }else if (o.clientValidation !== false){ // client validation failed
5565 this.failureType = Roo.form.Action.CLIENT_INVALID;
5566 this.form.afterAction(this, false);
5570 success : function(response)
5572 this.uploadComplete= true;
5573 if (this.haveProgress) {
5574 Roo.MessageBox.hide();
5578 var result = this.processResponse(response);
5579 if(result === true || result.success){
5580 this.form.afterAction(this, true);
5584 this.form.markInvalid(result.errors);
5585 this.failureType = Roo.form.Action.SERVER_INVALID;
5587 this.form.afterAction(this, false);
5589 failure : function(response)
5591 this.uploadComplete= true;
5592 if (this.haveProgress) {
5593 Roo.MessageBox.hide();
5596 this.response = response;
5597 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5598 this.form.afterAction(this, false);
5601 handleResponse : function(response){
5602 if(this.form.errorReader){
5603 var rs = this.form.errorReader.read(response);
5606 for(var i = 0, len = rs.records.length; i < len; i++) {
5607 var r = rs.records[i];
5611 if(errors.length < 1){
5615 success : rs.success,
5621 ret = Roo.decode(response.responseText);
5625 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5635 Roo.form.Action.Load = function(form, options){
5636 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5637 this.reader = this.form.reader;
5640 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5645 Roo.Ajax.request(Roo.apply(
5646 this.createCallback(), {
5647 method:this.getMethod(),
5648 url:this.getUrl(false),
5649 params:this.getParams()
5653 success : function(response){
5655 var result = this.processResponse(response);
5656 if(result === true || !result.success || !result.data){
5657 this.failureType = Roo.form.Action.LOAD_FAILURE;
5658 this.form.afterAction(this, false);
5661 this.form.clearInvalid();
5662 this.form.setValues(result.data);
5663 this.form.afterAction(this, true);
5666 handleResponse : function(response){
5667 if(this.form.reader){
5668 var rs = this.form.reader.read(response);
5669 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5671 success : rs.success,
5675 return Roo.decode(response.responseText);
5679 Roo.form.Action.ACTION_TYPES = {
5680 'load' : Roo.form.Action.Load,
5681 'submit' : Roo.form.Action.Submit
5690 * @class Roo.bootstrap.Form
5691 * @extends Roo.bootstrap.Component
5692 * Bootstrap Form class
5693 * @cfg {String} method GET | POST (default POST)
5694 * @cfg {String} labelAlign top | left (default top)
5695 * @cfg {String} align left | right - for navbars
5700 * @param {Object} config The config object
5704 Roo.bootstrap.Form = function(config){
5705 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5708 * @event clientvalidation
5709 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5710 * @param {Form} this
5711 * @param {Boolean} valid true if the form has passed client-side validation
5713 clientvalidation: true,
5715 * @event beforeaction
5716 * Fires before any action is performed. Return false to cancel the action.
5717 * @param {Form} this
5718 * @param {Action} action The action to be performed
5722 * @event actionfailed
5723 * Fires when an action fails.
5724 * @param {Form} this
5725 * @param {Action} action The action that failed
5727 actionfailed : true,
5729 * @event actioncomplete
5730 * Fires when an action is completed.
5731 * @param {Form} this
5732 * @param {Action} action The action that completed
5734 actioncomplete : true
5739 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5742 * @cfg {String} method
5743 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5748 * The URL to use for form actions if one isn't supplied in the action options.
5751 * @cfg {Boolean} fileUpload
5752 * Set to true if this form is a file upload.
5756 * @cfg {Object} baseParams
5757 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5761 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5765 * @cfg {Sting} align (left|right) for navbar forms
5770 activeAction : null,
5773 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5774 * element by passing it or its id or mask the form itself by passing in true.
5777 waitMsgTarget : false,
5782 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5783 * element by passing it or its id or mask the form itself by passing in true.
5787 getAutoCreate : function(){
5791 method : this.method || 'POST',
5792 id : this.id || Roo.id(),
5795 if (this.parent().xtype.match(/^Nav/)) {
5796 cfg.cls = 'navbar-form navbar-' + this.align;
5800 if (this.labelAlign == 'left' ) {
5801 cfg.cls += ' form-horizontal';
5807 initEvents : function()
5809 this.el.on('submit', this.onSubmit, this);
5810 this.el.on('keypress', function(e) {
5811 if (e.getCharCode() != 13) {
5820 onSubmit : function(e){
5825 * Returns true if client-side validation on the form is successful.
5828 isValid : function(){
5829 var items = this.getItems();
5831 items.each(function(f){
5840 * Returns true if any fields in this form have changed since their original load.
5843 isDirty : function(){
5845 var items = this.getItems();
5846 items.each(function(f){
5856 * Performs a predefined action (submit or load) or custom actions you define on this form.
5857 * @param {String} actionName The name of the action type
5858 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5859 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5860 * accept other config options):
5862 Property Type Description
5863 ---------------- --------------- ----------------------------------------------------------------------------------
5864 url String The url for the action (defaults to the form's url)
5865 method String The form method to use (defaults to the form's method, or POST if not defined)
5866 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5867 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5868 validate the form on the client (defaults to false)
5870 * @return {BasicForm} this
5872 doAction : function(action, options){
5873 if(typeof action == 'string'){
5874 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5876 if(this.fireEvent('beforeaction', this, action) !== false){
5877 this.beforeAction(action);
5878 action.run.defer(100, action);
5884 beforeAction : function(action){
5885 var o = action.options;
5887 // not really supported yet.. ??
5889 //if(this.waitMsgTarget === true){
5890 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5891 //}else if(this.waitMsgTarget){
5892 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5893 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5895 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5901 afterAction : function(action, success){
5902 this.activeAction = null;
5903 var o = action.options;
5905 //if(this.waitMsgTarget === true){
5907 //}else if(this.waitMsgTarget){
5908 // this.waitMsgTarget.unmask();
5910 // Roo.MessageBox.updateProgress(1);
5911 // Roo.MessageBox.hide();
5918 Roo.callback(o.success, o.scope, [this, action]);
5919 this.fireEvent('actioncomplete', this, action);
5923 // failure condition..
5924 // we have a scenario where updates need confirming.
5925 // eg. if a locking scenario exists..
5926 // we look for { errors : { needs_confirm : true }} in the response.
5928 (typeof(action.result) != 'undefined') &&
5929 (typeof(action.result.errors) != 'undefined') &&
5930 (typeof(action.result.errors.needs_confirm) != 'undefined')
5933 Roo.log("not supported yet");
5936 Roo.MessageBox.confirm(
5937 "Change requires confirmation",
5938 action.result.errorMsg,
5943 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5953 Roo.callback(o.failure, o.scope, [this, action]);
5954 // show an error message if no failed handler is set..
5955 if (!this.hasListener('actionfailed')) {
5956 Roo.log("need to add dialog support");
5958 Roo.MessageBox.alert("Error",
5959 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5960 action.result.errorMsg :
5961 "Saving Failed, please check your entries or try again"
5966 this.fireEvent('actionfailed', this, action);
5971 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5972 * @param {String} id The value to search for
5975 findField : function(id){
5976 var items = this.getItems();
5977 var field = items.get(id);
5979 items.each(function(f){
5980 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5987 return field || null;
5990 * Mark fields in this form invalid in bulk.
5991 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5992 * @return {BasicForm} this
5994 markInvalid : function(errors){
5995 if(errors instanceof Array){
5996 for(var i = 0, len = errors.length; i < len; i++){
5997 var fieldError = errors[i];
5998 var f = this.findField(fieldError.id);
6000 f.markInvalid(fieldError.msg);
6006 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6007 field.markInvalid(errors[id]);
6011 //Roo.each(this.childForms || [], function (f) {
6012 // f.markInvalid(errors);
6019 * Set values for fields in this form in bulk.
6020 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6021 * @return {BasicForm} this
6023 setValues : function(values){
6024 if(values instanceof Array){ // array of objects
6025 for(var i = 0, len = values.length; i < len; i++){
6027 var f = this.findField(v.id);
6029 f.setValue(v.value);
6030 if(this.trackResetOnLoad){
6031 f.originalValue = f.getValue();
6035 }else{ // object hash
6038 if(typeof values[id] != 'function' && (field = this.findField(id))){
6040 if (field.setFromData &&
6042 field.displayField &&
6043 // combos' with local stores can
6044 // be queried via setValue()
6045 // to set their value..
6046 (field.store && !field.store.isLocal)
6050 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6051 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6052 field.setFromData(sd);
6055 field.setValue(values[id]);
6059 if(this.trackResetOnLoad){
6060 field.originalValue = field.getValue();
6066 //Roo.each(this.childForms || [], function (f) {
6067 // f.setValues(values);
6074 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6075 * they are returned as an array.
6076 * @param {Boolean} asString
6079 getValues : function(asString){
6080 //if (this.childForms) {
6081 // copy values from the child forms
6082 // Roo.each(this.childForms, function (f) {
6083 // this.setValues(f.getValues());
6089 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6090 if(asString === true){
6093 return Roo.urlDecode(fs);
6097 * Returns the fields in this form as an object with key/value pairs.
6098 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6101 getFieldValues : function(with_hidden)
6103 var items = this.getItems();
6105 items.each(function(f){
6109 var v = f.getValue();
6110 if (f.inputType =='radio') {
6111 if (typeof(ret[f.getName()]) == 'undefined') {
6112 ret[f.getName()] = ''; // empty..
6115 if (!f.el.dom.checked) {
6123 // not sure if this supported any more..
6124 if ((typeof(v) == 'object') && f.getRawValue) {
6125 v = f.getRawValue() ; // dates..
6127 // combo boxes where name != hiddenName...
6128 if (f.name != f.getName()) {
6129 ret[f.name] = f.getRawValue();
6131 ret[f.getName()] = v;
6138 * Clears all invalid messages in this form.
6139 * @return {BasicForm} this
6141 clearInvalid : function(){
6142 var items = this.getItems();
6144 items.each(function(f){
6155 * @return {BasicForm} this
6158 var items = this.getItems();
6159 items.each(function(f){
6163 Roo.each(this.childForms || [], function (f) {
6170 getItems : function()
6172 var r=new Roo.util.MixedCollection(false, function(o){
6173 return o.id || (o.id = Roo.id());
6175 var iter = function(el) {
6182 Roo.each(el.items,function(e) {
6201 * Ext JS Library 1.1.1
6202 * Copyright(c) 2006-2007, Ext JS, LLC.
6204 * Originally Released Under LGPL - original licence link has changed is not relivant.
6207 * <script type="text/javascript">
6210 * @class Roo.form.VTypes
6211 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6214 Roo.form.VTypes = function(){
6215 // closure these in so they are only created once.
6216 var alpha = /^[a-zA-Z_]+$/;
6217 var alphanum = /^[a-zA-Z0-9_]+$/;
6218 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6219 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6221 // All these messages and functions are configurable
6224 * The function used to validate email addresses
6225 * @param {String} value The email address
6227 'email' : function(v){
6228 return email.test(v);
6231 * The error text to display when the email validation function returns false
6234 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6236 * The keystroke filter mask to be applied on email input
6239 'emailMask' : /[a-z0-9_\.\-@]/i,
6242 * The function used to validate URLs
6243 * @param {String} value The URL
6245 'url' : function(v){
6249 * The error text to display when the url validation function returns false
6252 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6255 * The function used to validate alpha values
6256 * @param {String} value The value
6258 'alpha' : function(v){
6259 return alpha.test(v);
6262 * The error text to display when the alpha validation function returns false
6265 'alphaText' : 'This field should only contain letters and _',
6267 * The keystroke filter mask to be applied on alpha input
6270 'alphaMask' : /[a-z_]/i,
6273 * The function used to validate alphanumeric values
6274 * @param {String} value The value
6276 'alphanum' : function(v){
6277 return alphanum.test(v);
6280 * The error text to display when the alphanumeric validation function returns false
6283 'alphanumText' : 'This field should only contain letters, numbers and _',
6285 * The keystroke filter mask to be applied on alphanumeric input
6288 'alphanumMask' : /[a-z0-9_]/i
6298 * @class Roo.bootstrap.Input
6299 * @extends Roo.bootstrap.Component
6300 * Bootstrap Input class
6301 * @cfg {Boolean} disabled is it disabled
6302 * @cfg {String} fieldLabel - the label associated
6303 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6304 * @cfg {String} name name of the input
6305 * @cfg {string} fieldLabel - the label associated
6306 * @cfg {string} inputType - input / file submit ...
6307 * @cfg {string} placeholder - placeholder to put in text.
6308 * @cfg {string} before - input group add on before
6309 * @cfg {string} after - input group add on after
6310 * @cfg {string} size - (lg|sm) or leave empty..
6311 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6312 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6313 * @cfg {Number} md colspan out of 12 for computer-sized screens
6314 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6315 * @cfg {string} value default value of the input
6316 * @cfg {Number} labelWidth set the width of label (0-12)
6317 * @cfg {String} labelAlign (top|left)
6318 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6319 * @cfg {String} align (left|center|right) Default left
6323 * Create a new Input
6324 * @param {Object} config The config object
6327 Roo.bootstrap.Input = function(config){
6328 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6333 * Fires when this field receives input focus.
6334 * @param {Roo.form.Field} this
6339 * Fires when this field loses input focus.
6340 * @param {Roo.form.Field} this
6345 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6346 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6347 * @param {Roo.form.Field} this
6348 * @param {Roo.EventObject} e The event object
6353 * Fires just before the field blurs if the field value has changed.
6354 * @param {Roo.form.Field} this
6355 * @param {Mixed} newValue The new value
6356 * @param {Mixed} oldValue The original value
6361 * Fires after the field has been marked as invalid.
6362 * @param {Roo.form.Field} this
6363 * @param {String} msg The validation message
6368 * Fires after the field has been validated with no errors.
6369 * @param {Roo.form.Field} this
6374 * Fires after the key up
6375 * @param {Roo.form.Field} this
6376 * @param {Roo.EventObject} e The event Object
6382 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6384 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6385 automatic validation (defaults to "keyup").
6387 validationEvent : "keyup",
6389 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6391 validateOnBlur : true,
6393 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6395 validationDelay : 250,
6397 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6399 focusClass : "x-form-focus", // not needed???
6403 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6405 invalidClass : "has-error",
6408 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6410 selectOnFocus : false,
6413 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6417 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6422 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6424 disableKeyFilter : false,
6427 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6431 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6435 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6437 blankText : "This field is required",
6440 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6444 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6446 maxLength : Number.MAX_VALUE,
6448 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6450 minLengthText : "The minimum length for this field is {0}",
6452 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6454 maxLengthText : "The maximum length for this field is {0}",
6458 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6459 * If available, this function will be called only after the basic validators all return true, and will be passed the
6460 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6464 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6465 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6466 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6470 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6494 parentLabelAlign : function()
6497 while (parent.parent()) {
6498 parent = parent.parent();
6499 if (typeof(parent.labelAlign) !='undefined') {
6500 return parent.labelAlign;
6507 getAutoCreate : function(){
6509 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6515 if(this.inputType != 'hidden'){
6516 cfg.cls = 'form-group' //input-group
6522 type : this.inputType,
6524 cls : 'form-control',
6525 placeholder : this.placeholder || ''
6530 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6533 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6534 input.maxLength = this.maxLength;
6537 if (this.disabled) {
6538 input.disabled=true;
6541 if (this.readOnly) {
6542 input.readonly=true;
6546 input.name = this.name;
6549 input.cls += ' input-' + this.size;
6552 ['xs','sm','md','lg'].map(function(size){
6553 if (settings[size]) {
6554 cfg.cls += ' col-' + size + '-' + settings[size];
6558 var inputblock = input;
6560 if (this.before || this.after) {
6563 cls : 'input-group',
6566 if (this.before && typeof(this.before) == 'string') {
6568 inputblock.cn.push({
6570 cls : 'roo-input-before input-group-addon',
6574 if (this.before && typeof(this.before) == 'object') {
6575 this.before = Roo.factory(this.before);
6576 Roo.log(this.before);
6577 inputblock.cn.push({
6579 cls : 'roo-input-before input-group-' +
6580 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6584 inputblock.cn.push(input);
6586 if (this.after && typeof(this.after) == 'string') {
6587 inputblock.cn.push({
6589 cls : 'roo-input-after input-group-addon',
6593 if (this.after && typeof(this.after) == 'object') {
6594 this.after = Roo.factory(this.after);
6595 Roo.log(this.after);
6596 inputblock.cn.push({
6598 cls : 'roo-input-after input-group-' +
6599 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6604 if (align ==='left' && this.fieldLabel.length) {
6605 Roo.log("left and has label");
6611 cls : 'control-label col-sm-' + this.labelWidth,
6612 html : this.fieldLabel
6616 cls : "col-sm-" + (12 - this.labelWidth),
6623 } else if ( this.fieldLabel.length) {
6629 //cls : 'input-group-addon',
6630 html : this.fieldLabel
6640 Roo.log(" no label && no align");
6649 Roo.log('input-parentType: ' + this.parentType);
6651 if (this.parentType === 'Navbar' && this.parent().bar) {
6652 cfg.cls += ' navbar-form';
6660 * return the real input element.
6662 inputEl: function ()
6664 return this.el.select('input.form-control',true).first();
6666 setDisabled : function(v)
6668 var i = this.inputEl().dom;
6670 i.removeAttribute('disabled');
6674 i.setAttribute('disabled','true');
6676 initEvents : function()
6679 this.inputEl().on("keydown" , this.fireKey, this);
6680 this.inputEl().on("focus", this.onFocus, this);
6681 this.inputEl().on("blur", this.onBlur, this);
6683 this.inputEl().relayEvent('keyup', this);
6685 // reference to original value for reset
6686 this.originalValue = this.getValue();
6687 //Roo.form.TextField.superclass.initEvents.call(this);
6688 if(this.validationEvent == 'keyup'){
6689 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6690 this.inputEl().on('keyup', this.filterValidation, this);
6692 else if(this.validationEvent !== false){
6693 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6696 if(this.selectOnFocus){
6697 this.on("focus", this.preFocus, this);
6700 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6701 this.inputEl().on("keypress", this.filterKeys, this);
6704 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6705 this.el.on("click", this.autoSize, this);
6708 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6709 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6712 if (typeof(this.before) == 'object') {
6713 this.before.render(this.el.select('.roo-input-before',true).first());
6715 if (typeof(this.after) == 'object') {
6716 this.after.render(this.el.select('.roo-input-after',true).first());
6721 filterValidation : function(e){
6722 if(!e.isNavKeyPress()){
6723 this.validationTask.delay(this.validationDelay);
6727 * Validates the field value
6728 * @return {Boolean} True if the value is valid, else false
6730 validate : function(){
6731 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6732 if(this.disabled || this.validateValue(this.getRawValue())){
6733 this.clearInvalid();
6741 * Validates a value according to the field's validation rules and marks the field as invalid
6742 * if the validation fails
6743 * @param {Mixed} value The value to validate
6744 * @return {Boolean} True if the value is valid, else false
6746 validateValue : function(value){
6747 if(value.length < 1) { // if it's blank
6748 if(this.allowBlank){
6749 this.clearInvalid();
6752 this.markInvalid(this.blankText);
6756 if(value.length < this.minLength){
6757 this.markInvalid(String.format(this.minLengthText, this.minLength));
6760 if(value.length > this.maxLength){
6761 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6765 var vt = Roo.form.VTypes;
6766 if(!vt[this.vtype](value, this)){
6767 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6771 if(typeof this.validator == "function"){
6772 var msg = this.validator(value);
6774 this.markInvalid(msg);
6778 if(this.regex && !this.regex.test(value)){
6779 this.markInvalid(this.regexText);
6788 fireKey : function(e){
6789 //Roo.log('field ' + e.getKey());
6790 if(e.isNavKeyPress()){
6791 this.fireEvent("specialkey", this, e);
6794 focus : function (selectText){
6796 this.inputEl().focus();
6797 if(selectText === true){
6798 this.inputEl().dom.select();
6804 onFocus : function(){
6805 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6806 // this.el.addClass(this.focusClass);
6809 this.hasFocus = true;
6810 this.startValue = this.getValue();
6811 this.fireEvent("focus", this);
6815 beforeBlur : Roo.emptyFn,
6819 onBlur : function(){
6821 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6822 //this.el.removeClass(this.focusClass);
6824 this.hasFocus = false;
6825 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6828 var v = this.getValue();
6829 if(String(v) !== String(this.startValue)){
6830 this.fireEvent('change', this, v, this.startValue);
6832 this.fireEvent("blur", this);
6836 * Resets the current field value to the originally loaded value and clears any validation messages
6839 this.setValue(this.originalValue);
6840 this.clearInvalid();
6843 * Returns the name of the field
6844 * @return {Mixed} name The name field
6846 getName: function(){
6850 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6851 * @return {Mixed} value The field value
6853 getValue : function(){
6854 return this.inputEl().getValue();
6857 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6858 * @return {Mixed} value The field value
6860 getRawValue : function(){
6861 var v = this.inputEl().getValue();
6867 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6868 * @param {Mixed} value The value to set
6870 setRawValue : function(v){
6871 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6874 selectText : function(start, end){
6875 var v = this.getRawValue();
6877 start = start === undefined ? 0 : start;
6878 end = end === undefined ? v.length : end;
6879 var d = this.inputEl().dom;
6880 if(d.setSelectionRange){
6881 d.setSelectionRange(start, end);
6882 }else if(d.createTextRange){
6883 var range = d.createTextRange();
6884 range.moveStart("character", start);
6885 range.moveEnd("character", v.length-end);
6892 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6893 * @param {Mixed} value The value to set
6895 setValue : function(v){
6898 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6904 processValue : function(value){
6905 if(this.stripCharsRe){
6906 var newValue = value.replace(this.stripCharsRe, '');
6907 if(newValue !== value){
6908 this.setRawValue(newValue);
6915 preFocus : function(){
6917 if(this.selectOnFocus){
6918 this.inputEl().dom.select();
6921 filterKeys : function(e){
6923 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6926 var c = e.getCharCode(), cc = String.fromCharCode(c);
6927 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6930 if(!this.maskRe.test(cc)){
6935 * Clear any invalid styles/messages for this field
6937 clearInvalid : function(){
6939 if(!this.el || this.preventMark){ // not rendered
6942 this.el.removeClass(this.invalidClass);
6944 switch(this.msgTarget){
6946 this.el.dom.qtip = '';
6949 this.el.dom.title = '';
6953 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6958 this.errorIcon.dom.qtip = '';
6959 this.errorIcon.hide();
6960 this.un('resize', this.alignErrorIcon, this);
6964 var t = Roo.getDom(this.msgTarget);
6966 t.style.display = 'none';
6970 this.fireEvent('valid', this);
6973 * Mark this field as invalid
6974 * @param {String} msg The validation message
6976 markInvalid : function(msg){
6977 if(!this.el || this.preventMark){ // not rendered
6980 this.el.addClass(this.invalidClass);
6982 msg = msg || this.invalidText;
6983 switch(this.msgTarget){
6985 this.el.dom.qtip = msg;
6986 this.el.dom.qclass = 'x-form-invalid-tip';
6987 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6988 Roo.QuickTips.enable();
6992 this.el.dom.title = msg;
6996 var elp = this.el.findParent('.x-form-element', 5, true);
6997 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6998 this.errorEl.setWidth(elp.getWidth(true)-20);
7000 this.errorEl.update(msg);
7001 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7004 if(!this.errorIcon){
7005 var elp = this.el.findParent('.x-form-element', 5, true);
7006 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7008 this.alignErrorIcon();
7009 this.errorIcon.dom.qtip = msg;
7010 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7011 this.errorIcon.show();
7012 this.on('resize', this.alignErrorIcon, this);
7015 var t = Roo.getDom(this.msgTarget);
7017 t.style.display = this.msgDisplay;
7021 this.fireEvent('invalid', this, msg);
7024 SafariOnKeyDown : function(event)
7026 // this is a workaround for a password hang bug on chrome/ webkit.
7028 var isSelectAll = false;
7030 if(this.inputEl().dom.selectionEnd > 0){
7031 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7033 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7034 event.preventDefault();
7039 if(isSelectAll){ // backspace and delete key
7041 event.preventDefault();
7042 // this is very hacky as keydown always get's upper case.
7044 var cc = String.fromCharCode(event.getCharCode());
7045 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7049 adjustWidth : function(tag, w){
7050 tag = tag.toLowerCase();
7051 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7052 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7056 if(tag == 'textarea'){
7059 }else if(Roo.isOpera){
7063 if(tag == 'textarea'){
7082 * @class Roo.bootstrap.TextArea
7083 * @extends Roo.bootstrap.Input
7084 * Bootstrap TextArea class
7085 * @cfg {Number} cols Specifies the visible width of a text area
7086 * @cfg {Number} rows Specifies the visible number of lines in a text area
7087 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7088 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7089 * @cfg {string} html text
7092 * Create a new TextArea
7093 * @param {Object} config The config object
7096 Roo.bootstrap.TextArea = function(config){
7097 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7101 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7111 getAutoCreate : function(){
7113 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7124 value : this.value || '',
7125 html: this.html || '',
7126 cls : 'form-control',
7127 placeholder : this.placeholder || ''
7131 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7132 input.maxLength = this.maxLength;
7136 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7140 input.cols = this.cols;
7143 if (this.readOnly) {
7144 input.readonly = true;
7148 input.name = this.name;
7152 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7156 ['xs','sm','md','lg'].map(function(size){
7157 if (settings[size]) {
7158 cfg.cls += ' col-' + size + '-' + settings[size];
7162 var inputblock = input;
7164 if (this.before || this.after) {
7167 cls : 'input-group',
7171 inputblock.cn.push({
7173 cls : 'input-group-addon',
7177 inputblock.cn.push(input);
7179 inputblock.cn.push({
7181 cls : 'input-group-addon',
7188 if (align ==='left' && this.fieldLabel.length) {
7189 Roo.log("left and has label");
7195 cls : 'control-label col-sm-' + this.labelWidth,
7196 html : this.fieldLabel
7200 cls : "col-sm-" + (12 - this.labelWidth),
7207 } else if ( this.fieldLabel.length) {
7213 //cls : 'input-group-addon',
7214 html : this.fieldLabel
7224 Roo.log(" no label && no align");
7234 if (this.disabled) {
7235 input.disabled=true;
7242 * return the real textarea element.
7244 inputEl: function ()
7246 return this.el.select('textarea.form-control',true).first();
7254 * trigger field - base class for combo..
7259 * @class Roo.bootstrap.TriggerField
7260 * @extends Roo.bootstrap.Input
7261 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7262 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7263 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7264 * for which you can provide a custom implementation. For example:
7266 var trigger = new Roo.bootstrap.TriggerField();
7267 trigger.onTriggerClick = myTriggerFn;
7268 trigger.applyTo('my-field');
7271 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7272 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7273 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7274 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7276 * Create a new TriggerField.
7277 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7278 * to the base TextField)
7280 Roo.bootstrap.TriggerField = function(config){
7281 this.mimicing = false;
7282 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7285 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7287 * @cfg {String} triggerClass A CSS class to apply to the trigger
7290 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7294 /** @cfg {Boolean} grow @hide */
7295 /** @cfg {Number} growMin @hide */
7296 /** @cfg {Number} growMax @hide */
7302 autoSize: Roo.emptyFn,
7309 actionMode : 'wrap',
7313 getAutoCreate : function(){
7315 var parent = this.parent();
7317 var align = this.labelAlign || this.parentLabelAlign();
7322 cls: 'form-group' //input-group
7329 type : this.inputType,
7330 cls : 'form-control',
7331 autocomplete: 'off',
7332 placeholder : this.placeholder || ''
7336 input.name = this.name;
7339 input.cls += ' input-' + this.size;
7342 if (this.disabled) {
7343 input.disabled=true;
7346 var inputblock = input;
7348 if (this.before || this.after) {
7351 cls : 'input-group',
7355 inputblock.cn.push({
7357 cls : 'input-group-addon',
7361 inputblock.cn.push(input);
7363 inputblock.cn.push({
7365 cls : 'input-group-addon',
7378 cls: 'form-hidden-field'
7386 Roo.log('multiple');
7394 cls: 'form-hidden-field'
7398 cls: 'select2-choices',
7402 cls: 'select2-search-field',
7415 cls: 'select2-container input-group',
7420 cls: 'typeahead typeahead-long dropdown-menu',
7421 style: 'display:none'
7429 cls : 'input-group-addon btn dropdown-toggle',
7437 cls: 'combobox-clear',
7451 combobox.cls += ' select2-container-multi';
7454 if (align ==='left' && this.fieldLabel.length) {
7456 Roo.log("left and has label");
7462 cls : 'control-label col-sm-' + this.labelWidth,
7463 html : this.fieldLabel
7467 cls : "col-sm-" + (12 - this.labelWidth),
7474 } else if ( this.fieldLabel.length) {
7480 //cls : 'input-group-addon',
7481 html : this.fieldLabel
7491 Roo.log(" no label && no align");
7498 ['xs','sm','md','lg'].map(function(size){
7499 if (settings[size]) {
7500 cfg.cls += ' col-' + size + '-' + settings[size];
7511 onResize : function(w, h){
7512 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7513 // if(typeof w == 'number'){
7514 // var x = w - this.trigger.getWidth();
7515 // this.inputEl().setWidth(this.adjustWidth('input', x));
7516 // this.trigger.setStyle('left', x+'px');
7521 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7524 getResizeEl : function(){
7525 return this.inputEl();
7529 getPositionEl : function(){
7530 return this.inputEl();
7534 alignErrorIcon : function(){
7535 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7539 initEvents : function(){
7541 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7542 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7544 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7545 if(this.hideTrigger){
7546 this.trigger.setDisplayed(false);
7548 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7552 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7555 //this.trigger.addClassOnOver('x-form-trigger-over');
7556 //this.trigger.addClassOnClick('x-form-trigger-click');
7559 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7564 initTrigger : function(){
7569 onDestroy : function(){
7571 this.trigger.removeAllListeners();
7572 // this.trigger.remove();
7575 // this.wrap.remove();
7577 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7581 onFocus : function(){
7582 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7585 this.wrap.addClass('x-trigger-wrap-focus');
7586 this.mimicing = true;
7587 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7588 if(this.monitorTab){
7589 this.el.on("keydown", this.checkTab, this);
7596 checkTab : function(e){
7597 if(e.getKey() == e.TAB){
7603 onBlur : function(){
7608 mimicBlur : function(e, t){
7610 if(!this.wrap.contains(t) && this.validateBlur()){
7617 triggerBlur : function(){
7618 this.mimicing = false;
7619 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7620 if(this.monitorTab){
7621 this.el.un("keydown", this.checkTab, this);
7623 //this.wrap.removeClass('x-trigger-wrap-focus');
7624 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7628 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7629 validateBlur : function(e, t){
7634 onDisable : function(){
7635 this.inputEl().dom.disabled = true;
7636 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7638 // this.wrap.addClass('x-item-disabled');
7643 onEnable : function(){
7644 this.inputEl().dom.disabled = false;
7645 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7647 // this.el.removeClass('x-item-disabled');
7652 onShow : function(){
7653 var ae = this.getActionEl();
7656 ae.dom.style.display = '';
7657 ae.dom.style.visibility = 'visible';
7663 onHide : function(){
7664 var ae = this.getActionEl();
7665 ae.dom.style.display = 'none';
7669 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7670 * by an implementing function.
7672 * @param {EventObject} e
7674 onTriggerClick : Roo.emptyFn
7678 * Ext JS Library 1.1.1
7679 * Copyright(c) 2006-2007, Ext JS, LLC.
7681 * Originally Released Under LGPL - original licence link has changed is not relivant.
7684 * <script type="text/javascript">
7689 * @class Roo.data.SortTypes
7691 * Defines the default sorting (casting?) comparison functions used when sorting data.
7693 Roo.data.SortTypes = {
7695 * Default sort that does nothing
7696 * @param {Mixed} s The value being converted
7697 * @return {Mixed} The comparison value
7704 * The regular expression used to strip tags
7708 stripTagsRE : /<\/?[^>]+>/gi,
7711 * Strips all HTML tags to sort on text only
7712 * @param {Mixed} s The value being converted
7713 * @return {String} The comparison value
7715 asText : function(s){
7716 return String(s).replace(this.stripTagsRE, "");
7720 * Strips all HTML tags to sort on text only - Case insensitive
7721 * @param {Mixed} s The value being converted
7722 * @return {String} The comparison value
7724 asUCText : function(s){
7725 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7729 * Case insensitive string
7730 * @param {Mixed} s The value being converted
7731 * @return {String} The comparison value
7733 asUCString : function(s) {
7734 return String(s).toUpperCase();
7739 * @param {Mixed} s The value being converted
7740 * @return {Number} The comparison value
7742 asDate : function(s) {
7746 if(s instanceof Date){
7749 return Date.parse(String(s));
7754 * @param {Mixed} s The value being converted
7755 * @return {Float} The comparison value
7757 asFloat : function(s) {
7758 var val = parseFloat(String(s).replace(/,/g, ""));
7759 if(isNaN(val)) val = 0;
7765 * @param {Mixed} s The value being converted
7766 * @return {Number} The comparison value
7768 asInt : function(s) {
7769 var val = parseInt(String(s).replace(/,/g, ""));
7770 if(isNaN(val)) val = 0;
7775 * Ext JS Library 1.1.1
7776 * Copyright(c) 2006-2007, Ext JS, LLC.
7778 * Originally Released Under LGPL - original licence link has changed is not relivant.
7781 * <script type="text/javascript">
7785 * @class Roo.data.Record
7786 * Instances of this class encapsulate both record <em>definition</em> information, and record
7787 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7788 * to access Records cached in an {@link Roo.data.Store} object.<br>
7790 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7791 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7794 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7796 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7797 * {@link #create}. The parameters are the same.
7798 * @param {Array} data An associative Array of data values keyed by the field name.
7799 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7800 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7801 * not specified an integer id is generated.
7803 Roo.data.Record = function(data, id){
7804 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7809 * Generate a constructor for a specific record layout.
7810 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7811 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7812 * Each field definition object may contain the following properties: <ul>
7813 * <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,
7814 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7815 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7816 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7817 * is being used, then this is a string containing the javascript expression to reference the data relative to
7818 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7819 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7820 * this may be omitted.</p></li>
7821 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7822 * <ul><li>auto (Default, implies no conversion)</li>
7827 * <li>date</li></ul></p></li>
7828 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7829 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7830 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7831 * by the Reader into an object that will be stored in the Record. It is passed the
7832 * following parameters:<ul>
7833 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7835 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7837 * <br>usage:<br><pre><code>
7838 var TopicRecord = Roo.data.Record.create(
7839 {name: 'title', mapping: 'topic_title'},
7840 {name: 'author', mapping: 'username'},
7841 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7842 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7843 {name: 'lastPoster', mapping: 'user2'},
7844 {name: 'excerpt', mapping: 'post_text'}
7847 var myNewRecord = new TopicRecord({
7848 title: 'Do my job please',
7851 lastPost: new Date(),
7852 lastPoster: 'Animal',
7853 excerpt: 'No way dude!'
7855 myStore.add(myNewRecord);
7860 Roo.data.Record.create = function(o){
7862 f.superclass.constructor.apply(this, arguments);
7864 Roo.extend(f, Roo.data.Record);
7865 var p = f.prototype;
7866 p.fields = new Roo.util.MixedCollection(false, function(field){
7869 for(var i = 0, len = o.length; i < len; i++){
7870 p.fields.add(new Roo.data.Field(o[i]));
7872 f.getField = function(name){
7873 return p.fields.get(name);
7878 Roo.data.Record.AUTO_ID = 1000;
7879 Roo.data.Record.EDIT = 'edit';
7880 Roo.data.Record.REJECT = 'reject';
7881 Roo.data.Record.COMMIT = 'commit';
7883 Roo.data.Record.prototype = {
7885 * Readonly flag - true if this record has been modified.
7894 join : function(store){
7899 * Set the named field to the specified value.
7900 * @param {String} name The name of the field to set.
7901 * @param {Object} value The value to set the field to.
7903 set : function(name, value){
7904 if(this.data[name] == value){
7911 if(typeof this.modified[name] == 'undefined'){
7912 this.modified[name] = this.data[name];
7914 this.data[name] = value;
7915 if(!this.editing && this.store){
7916 this.store.afterEdit(this);
7921 * Get the value of the named field.
7922 * @param {String} name The name of the field to get the value of.
7923 * @return {Object} The value of the field.
7925 get : function(name){
7926 return this.data[name];
7930 beginEdit : function(){
7931 this.editing = true;
7936 cancelEdit : function(){
7937 this.editing = false;
7938 delete this.modified;
7942 endEdit : function(){
7943 this.editing = false;
7944 if(this.dirty && this.store){
7945 this.store.afterEdit(this);
7950 * Usually called by the {@link Roo.data.Store} which owns the Record.
7951 * Rejects all changes made to the Record since either creation, or the last commit operation.
7952 * Modified fields are reverted to their original values.
7954 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7955 * of reject operations.
7957 reject : function(){
7958 var m = this.modified;
7960 if(typeof m[n] != "function"){
7961 this.data[n] = m[n];
7965 delete this.modified;
7966 this.editing = false;
7968 this.store.afterReject(this);
7973 * Usually called by the {@link Roo.data.Store} which owns the Record.
7974 * Commits all changes made to the Record since either creation, or the last commit operation.
7976 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7977 * of commit operations.
7979 commit : function(){
7981 delete this.modified;
7982 this.editing = false;
7984 this.store.afterCommit(this);
7989 hasError : function(){
7990 return this.error != null;
7994 clearError : function(){
7999 * Creates a copy of this record.
8000 * @param {String} id (optional) A new record id if you don't want to use this record's id
8003 copy : function(newId) {
8004 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8008 * Ext JS Library 1.1.1
8009 * Copyright(c) 2006-2007, Ext JS, LLC.
8011 * Originally Released Under LGPL - original licence link has changed is not relivant.
8014 * <script type="text/javascript">
8020 * @class Roo.data.Store
8021 * @extends Roo.util.Observable
8022 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8023 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8025 * 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
8026 * has no knowledge of the format of the data returned by the Proxy.<br>
8028 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8029 * instances from the data object. These records are cached and made available through accessor functions.
8031 * Creates a new Store.
8032 * @param {Object} config A config object containing the objects needed for the Store to access data,
8033 * and read the data into Records.
8035 Roo.data.Store = function(config){
8036 this.data = new Roo.util.MixedCollection(false);
8037 this.data.getKey = function(o){
8040 this.baseParams = {};
8047 "multisort" : "_multisort"
8050 if(config && config.data){
8051 this.inlineData = config.data;
8055 Roo.apply(this, config);
8057 if(this.reader){ // reader passed
8058 this.reader = Roo.factory(this.reader, Roo.data);
8059 this.reader.xmodule = this.xmodule || false;
8060 if(!this.recordType){
8061 this.recordType = this.reader.recordType;
8063 if(this.reader.onMetaChange){
8064 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8068 if(this.recordType){
8069 this.fields = this.recordType.prototype.fields;
8075 * @event datachanged
8076 * Fires when the data cache has changed, and a widget which is using this Store
8077 * as a Record cache should refresh its view.
8078 * @param {Store} this
8083 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8084 * @param {Store} this
8085 * @param {Object} meta The JSON metadata
8090 * Fires when Records have been added to the Store
8091 * @param {Store} this
8092 * @param {Roo.data.Record[]} records The array of Records added
8093 * @param {Number} index The index at which the record(s) were added
8098 * Fires when a Record has been removed from the Store
8099 * @param {Store} this
8100 * @param {Roo.data.Record} record The Record that was removed
8101 * @param {Number} index The index at which the record was removed
8106 * Fires when a Record has been updated
8107 * @param {Store} this
8108 * @param {Roo.data.Record} record The Record that was updated
8109 * @param {String} operation The update operation being performed. Value may be one of:
8111 Roo.data.Record.EDIT
8112 Roo.data.Record.REJECT
8113 Roo.data.Record.COMMIT
8119 * Fires when the data cache has been cleared.
8120 * @param {Store} this
8125 * Fires before a request is made for a new data object. If the beforeload handler returns false
8126 * the load action will be canceled.
8127 * @param {Store} this
8128 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8132 * @event beforeloadadd
8133 * Fires after a new set of Records has been loaded.
8134 * @param {Store} this
8135 * @param {Roo.data.Record[]} records The Records that were loaded
8136 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8138 beforeloadadd : true,
8141 * Fires after a new set of Records has been loaded, before they are added to the store.
8142 * @param {Store} this
8143 * @param {Roo.data.Record[]} records The Records that were loaded
8144 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8145 * @params {Object} return from reader
8149 * @event loadexception
8150 * Fires if an exception occurs in the Proxy during loading.
8151 * Called with the signature of the Proxy's "loadexception" event.
8152 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8155 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8156 * @param {Object} load options
8157 * @param {Object} jsonData from your request (normally this contains the Exception)
8159 loadexception : true
8163 this.proxy = Roo.factory(this.proxy, Roo.data);
8164 this.proxy.xmodule = this.xmodule || false;
8165 this.relayEvents(this.proxy, ["loadexception"]);
8167 this.sortToggle = {};
8168 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8170 Roo.data.Store.superclass.constructor.call(this);
8172 if(this.inlineData){
8173 this.loadData(this.inlineData);
8174 delete this.inlineData;
8178 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8180 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8181 * without a remote query - used by combo/forms at present.
8185 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8188 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8191 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8192 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8195 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8196 * on any HTTP request
8199 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8202 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8206 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8207 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8212 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8213 * loaded or when a record is removed. (defaults to false).
8215 pruneModifiedRecords : false,
8221 * Add Records to the Store and fires the add event.
8222 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8224 add : function(records){
8225 records = [].concat(records);
8226 for(var i = 0, len = records.length; i < len; i++){
8227 records[i].join(this);
8229 var index = this.data.length;
8230 this.data.addAll(records);
8231 this.fireEvent("add", this, records, index);
8235 * Remove a Record from the Store and fires the remove event.
8236 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8238 remove : function(record){
8239 var index = this.data.indexOf(record);
8240 this.data.removeAt(index);
8241 if(this.pruneModifiedRecords){
8242 this.modified.remove(record);
8244 this.fireEvent("remove", this, record, index);
8248 * Remove all Records from the Store and fires the clear event.
8250 removeAll : function(){
8252 if(this.pruneModifiedRecords){
8255 this.fireEvent("clear", this);
8259 * Inserts Records to the Store at the given index and fires the add event.
8260 * @param {Number} index The start index at which to insert the passed Records.
8261 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8263 insert : function(index, records){
8264 records = [].concat(records);
8265 for(var i = 0, len = records.length; i < len; i++){
8266 this.data.insert(index, records[i]);
8267 records[i].join(this);
8269 this.fireEvent("add", this, records, index);
8273 * Get the index within the cache of the passed Record.
8274 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8275 * @return {Number} The index of the passed Record. Returns -1 if not found.
8277 indexOf : function(record){
8278 return this.data.indexOf(record);
8282 * Get the index within the cache of the Record with the passed id.
8283 * @param {String} id The id of the Record to find.
8284 * @return {Number} The index of the Record. Returns -1 if not found.
8286 indexOfId : function(id){
8287 return this.data.indexOfKey(id);
8291 * Get the Record with the specified id.
8292 * @param {String} id The id of the Record to find.
8293 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8295 getById : function(id){
8296 return this.data.key(id);
8300 * Get the Record at the specified index.
8301 * @param {Number} index The index of the Record to find.
8302 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8304 getAt : function(index){
8305 return this.data.itemAt(index);
8309 * Returns a range of Records between specified indices.
8310 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8311 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8312 * @return {Roo.data.Record[]} An array of Records
8314 getRange : function(start, end){
8315 return this.data.getRange(start, end);
8319 storeOptions : function(o){
8320 o = Roo.apply({}, o);
8323 this.lastOptions = o;
8327 * Loads the Record cache from the configured Proxy using the configured Reader.
8329 * If using remote paging, then the first load call must specify the <em>start</em>
8330 * and <em>limit</em> properties in the options.params property to establish the initial
8331 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8333 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8334 * and this call will return before the new data has been loaded. Perform any post-processing
8335 * in a callback function, or in a "load" event handler.</strong>
8337 * @param {Object} options An object containing properties which control loading options:<ul>
8338 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8339 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8340 * passed the following arguments:<ul>
8341 * <li>r : Roo.data.Record[]</li>
8342 * <li>options: Options object from the load call</li>
8343 * <li>success: Boolean success indicator</li></ul></li>
8344 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8345 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8348 load : function(options){
8349 options = options || {};
8350 if(this.fireEvent("beforeload", this, options) !== false){
8351 this.storeOptions(options);
8352 var p = Roo.apply(options.params || {}, this.baseParams);
8353 // if meta was not loaded from remote source.. try requesting it.
8354 if (!this.reader.metaFromRemote) {
8357 if(this.sortInfo && this.remoteSort){
8358 var pn = this.paramNames;
8359 p[pn["sort"]] = this.sortInfo.field;
8360 p[pn["dir"]] = this.sortInfo.direction;
8362 if (this.multiSort) {
8363 var pn = this.paramNames;
8364 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8367 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8372 * Reloads the Record cache from the configured Proxy using the configured Reader and
8373 * the options from the last load operation performed.
8374 * @param {Object} options (optional) An object containing properties which may override the options
8375 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8376 * the most recently used options are reused).
8378 reload : function(options){
8379 this.load(Roo.applyIf(options||{}, this.lastOptions));
8383 // Called as a callback by the Reader during a load operation.
8384 loadRecords : function(o, options, success){
8385 if(!o || success === false){
8386 if(success !== false){
8387 this.fireEvent("load", this, [], options, o);
8389 if(options.callback){
8390 options.callback.call(options.scope || this, [], options, false);
8394 // if data returned failure - throw an exception.
8395 if (o.success === false) {
8396 // show a message if no listener is registered.
8397 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8398 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8400 // loadmask wil be hooked into this..
8401 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8404 var r = o.records, t = o.totalRecords || r.length;
8406 this.fireEvent("beforeloadadd", this, r, options, o);
8408 if(!options || options.add !== true){
8409 if(this.pruneModifiedRecords){
8412 for(var i = 0, len = r.length; i < len; i++){
8416 this.data = this.snapshot;
8417 delete this.snapshot;
8420 this.data.addAll(r);
8421 this.totalLength = t;
8423 this.fireEvent("datachanged", this);
8425 this.totalLength = Math.max(t, this.data.length+r.length);
8428 this.fireEvent("load", this, r, options, o);
8429 if(options.callback){
8430 options.callback.call(options.scope || this, r, options, true);
8436 * Loads data from a passed data block. A Reader which understands the format of the data
8437 * must have been configured in the constructor.
8438 * @param {Object} data The data block from which to read the Records. The format of the data expected
8439 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8440 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8442 loadData : function(o, append){
8443 var r = this.reader.readRecords(o);
8444 this.loadRecords(r, {add: append}, true);
8448 * Gets the number of cached records.
8450 * <em>If using paging, this may not be the total size of the dataset. If the data object
8451 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8452 * the data set size</em>
8454 getCount : function(){
8455 return this.data.length || 0;
8459 * Gets the total number of records in the dataset as returned by the server.
8461 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8462 * the dataset size</em>
8464 getTotalCount : function(){
8465 return this.totalLength || 0;
8469 * Returns the sort state of the Store as an object with two properties:
8471 field {String} The name of the field by which the Records are sorted
8472 direction {String} The sort order, "ASC" or "DESC"
8475 getSortState : function(){
8476 return this.sortInfo;
8480 applySort : function(){
8481 if(this.sortInfo && !this.remoteSort){
8482 var s = this.sortInfo, f = s.field;
8483 var st = this.fields.get(f).sortType;
8484 var fn = function(r1, r2){
8485 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8486 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8488 this.data.sort(s.direction, fn);
8489 if(this.snapshot && this.snapshot != this.data){
8490 this.snapshot.sort(s.direction, fn);
8496 * Sets the default sort column and order to be used by the next load operation.
8497 * @param {String} fieldName The name of the field to sort by.
8498 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8500 setDefaultSort : function(field, dir){
8501 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8506 * If remote sorting is used, the sort is performed on the server, and the cache is
8507 * reloaded. If local sorting is used, the cache is sorted internally.
8508 * @param {String} fieldName The name of the field to sort by.
8509 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8511 sort : function(fieldName, dir){
8512 var f = this.fields.get(fieldName);
8514 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8516 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8517 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8522 this.sortToggle[f.name] = dir;
8523 this.sortInfo = {field: f.name, direction: dir};
8524 if(!this.remoteSort){
8526 this.fireEvent("datachanged", this);
8528 this.load(this.lastOptions);
8533 * Calls the specified function for each of the Records in the cache.
8534 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8535 * Returning <em>false</em> aborts and exits the iteration.
8536 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8538 each : function(fn, scope){
8539 this.data.each(fn, scope);
8543 * Gets all records modified since the last commit. Modified records are persisted across load operations
8544 * (e.g., during paging).
8545 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8547 getModifiedRecords : function(){
8548 return this.modified;
8552 createFilterFn : function(property, value, anyMatch){
8553 if(!value.exec){ // not a regex
8554 value = String(value);
8555 if(value.length == 0){
8558 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8561 return value.test(r.data[property]);
8566 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8567 * @param {String} property A field on your records
8568 * @param {Number} start The record index to start at (defaults to 0)
8569 * @param {Number} end The last record index to include (defaults to length - 1)
8570 * @return {Number} The sum
8572 sum : function(property, start, end){
8573 var rs = this.data.items, v = 0;
8575 end = (end || end === 0) ? end : rs.length-1;
8577 for(var i = start; i <= end; i++){
8578 v += (rs[i].data[property] || 0);
8584 * Filter the records by a specified property.
8585 * @param {String} field A field on your records
8586 * @param {String/RegExp} value Either a string that the field
8587 * should start with or a RegExp to test against the field
8588 * @param {Boolean} anyMatch True to match any part not just the beginning
8590 filter : function(property, value, anyMatch){
8591 var fn = this.createFilterFn(property, value, anyMatch);
8592 return fn ? this.filterBy(fn) : this.clearFilter();
8596 * Filter by a function. The specified function will be called with each
8597 * record in this data source. If the function returns true the record is included,
8598 * otherwise it is filtered.
8599 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8600 * @param {Object} scope (optional) The scope of the function (defaults to this)
8602 filterBy : function(fn, scope){
8603 this.snapshot = this.snapshot || this.data;
8604 this.data = this.queryBy(fn, scope||this);
8605 this.fireEvent("datachanged", this);
8609 * Query the records by a specified property.
8610 * @param {String} field A field on your records
8611 * @param {String/RegExp} value Either a string that the field
8612 * should start with or a RegExp to test against the field
8613 * @param {Boolean} anyMatch True to match any part not just the beginning
8614 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8616 query : function(property, value, anyMatch){
8617 var fn = this.createFilterFn(property, value, anyMatch);
8618 return fn ? this.queryBy(fn) : this.data.clone();
8622 * Query by a function. The specified function will be called with each
8623 * record in this data source. If the function returns true the record is included
8625 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8626 * @param {Object} scope (optional) The scope of the function (defaults to this)
8627 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8629 queryBy : function(fn, scope){
8630 var data = this.snapshot || this.data;
8631 return data.filterBy(fn, scope||this);
8635 * Collects unique values for a particular dataIndex from this store.
8636 * @param {String} dataIndex The property to collect
8637 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8638 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8639 * @return {Array} An array of the unique values
8641 collect : function(dataIndex, allowNull, bypassFilter){
8642 var d = (bypassFilter === true && this.snapshot) ?
8643 this.snapshot.items : this.data.items;
8644 var v, sv, r = [], l = {};
8645 for(var i = 0, len = d.length; i < len; i++){
8646 v = d[i].data[dataIndex];
8648 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8657 * Revert to a view of the Record cache with no filtering applied.
8658 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8660 clearFilter : function(suppressEvent){
8661 if(this.snapshot && this.snapshot != this.data){
8662 this.data = this.snapshot;
8663 delete this.snapshot;
8664 if(suppressEvent !== true){
8665 this.fireEvent("datachanged", this);
8671 afterEdit : function(record){
8672 if(this.modified.indexOf(record) == -1){
8673 this.modified.push(record);
8675 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8679 afterReject : function(record){
8680 this.modified.remove(record);
8681 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8685 afterCommit : function(record){
8686 this.modified.remove(record);
8687 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8691 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8692 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8694 commitChanges : function(){
8695 var m = this.modified.slice(0);
8697 for(var i = 0, len = m.length; i < len; i++){
8703 * Cancel outstanding changes on all changed records.
8705 rejectChanges : function(){
8706 var m = this.modified.slice(0);
8708 for(var i = 0, len = m.length; i < len; i++){
8713 onMetaChange : function(meta, rtype, o){
8714 this.recordType = rtype;
8715 this.fields = rtype.prototype.fields;
8716 delete this.snapshot;
8717 this.sortInfo = meta.sortInfo || this.sortInfo;
8719 this.fireEvent('metachange', this, this.reader.meta);
8722 moveIndex : function(data, type)
8724 var index = this.indexOf(data);
8726 var newIndex = index + type;
8730 this.insert(newIndex, data);
8735 * Ext JS Library 1.1.1
8736 * Copyright(c) 2006-2007, Ext JS, LLC.
8738 * Originally Released Under LGPL - original licence link has changed is not relivant.
8741 * <script type="text/javascript">
8745 * @class Roo.data.SimpleStore
8746 * @extends Roo.data.Store
8747 * Small helper class to make creating Stores from Array data easier.
8748 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8749 * @cfg {Array} fields An array of field definition objects, or field name strings.
8750 * @cfg {Array} data The multi-dimensional array of data
8752 * @param {Object} config
8754 Roo.data.SimpleStore = function(config){
8755 Roo.data.SimpleStore.superclass.constructor.call(this, {
8757 reader: new Roo.data.ArrayReader({
8760 Roo.data.Record.create(config.fields)
8762 proxy : new Roo.data.MemoryProxy(config.data)
8766 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8768 * Ext JS Library 1.1.1
8769 * Copyright(c) 2006-2007, Ext JS, LLC.
8771 * Originally Released Under LGPL - original licence link has changed is not relivant.
8774 * <script type="text/javascript">
8779 * @extends Roo.data.Store
8780 * @class Roo.data.JsonStore
8781 * Small helper class to make creating Stores for JSON data easier. <br/>
8783 var store = new Roo.data.JsonStore({
8784 url: 'get-images.php',
8786 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8789 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8790 * JsonReader and HttpProxy (unless inline data is provided).</b>
8791 * @cfg {Array} fields An array of field definition objects, or field name strings.
8793 * @param {Object} config
8795 Roo.data.JsonStore = function(c){
8796 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8797 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8798 reader: new Roo.data.JsonReader(c, c.fields)
8801 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8803 * Ext JS Library 1.1.1
8804 * Copyright(c) 2006-2007, Ext JS, LLC.
8806 * Originally Released Under LGPL - original licence link has changed is not relivant.
8809 * <script type="text/javascript">
8813 Roo.data.Field = function(config){
8814 if(typeof config == "string"){
8815 config = {name: config};
8817 Roo.apply(this, config);
8823 var st = Roo.data.SortTypes;
8824 // named sortTypes are supported, here we look them up
8825 if(typeof this.sortType == "string"){
8826 this.sortType = st[this.sortType];
8829 // set default sortType for strings and dates
8833 this.sortType = st.asUCString;
8836 this.sortType = st.asDate;
8839 this.sortType = st.none;
8844 var stripRe = /[\$,%]/g;
8846 // prebuilt conversion function for this field, instead of
8847 // switching every time we're reading a value
8849 var cv, dateFormat = this.dateFormat;
8854 cv = function(v){ return v; };
8857 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8861 return v !== undefined && v !== null && v !== '' ?
8862 parseInt(String(v).replace(stripRe, ""), 10) : '';
8867 return v !== undefined && v !== null && v !== '' ?
8868 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8873 cv = function(v){ return v === true || v === "true" || v == 1; };
8880 if(v instanceof Date){
8884 if(dateFormat == "timestamp"){
8885 return new Date(v*1000);
8887 return Date.parseDate(v, dateFormat);
8889 var parsed = Date.parse(v);
8890 return parsed ? new Date(parsed) : null;
8899 Roo.data.Field.prototype = {
8907 * Ext JS Library 1.1.1
8908 * Copyright(c) 2006-2007, Ext JS, LLC.
8910 * Originally Released Under LGPL - original licence link has changed is not relivant.
8913 * <script type="text/javascript">
8916 // Base class for reading structured data from a data source. This class is intended to be
8917 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8920 * @class Roo.data.DataReader
8921 * Base class for reading structured data from a data source. This class is intended to be
8922 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8925 Roo.data.DataReader = function(meta, recordType){
8929 this.recordType = recordType instanceof Array ?
8930 Roo.data.Record.create(recordType) : recordType;
8933 Roo.data.DataReader.prototype = {
8935 * Create an empty record
8936 * @param {Object} data (optional) - overlay some values
8937 * @return {Roo.data.Record} record created.
8939 newRow : function(d) {
8941 this.recordType.prototype.fields.each(function(c) {
8943 case 'int' : da[c.name] = 0; break;
8944 case 'date' : da[c.name] = new Date(); break;
8945 case 'float' : da[c.name] = 0.0; break;
8946 case 'boolean' : da[c.name] = false; break;
8947 default : da[c.name] = ""; break;
8951 return new this.recordType(Roo.apply(da, d));
8956 * Ext JS Library 1.1.1
8957 * Copyright(c) 2006-2007, Ext JS, LLC.
8959 * Originally Released Under LGPL - original licence link has changed is not relivant.
8962 * <script type="text/javascript">
8966 * @class Roo.data.DataProxy
8967 * @extends Roo.data.Observable
8968 * This class is an abstract base class for implementations which provide retrieval of
8969 * unformatted data objects.<br>
8971 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8972 * (of the appropriate type which knows how to parse the data object) to provide a block of
8973 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8975 * Custom implementations must implement the load method as described in
8976 * {@link Roo.data.HttpProxy#load}.
8978 Roo.data.DataProxy = function(){
8982 * Fires before a network request is made to retrieve a data object.
8983 * @param {Object} This DataProxy object.
8984 * @param {Object} params The params parameter to the load function.
8989 * Fires before the load method's callback is called.
8990 * @param {Object} This DataProxy object.
8991 * @param {Object} o The data object.
8992 * @param {Object} arg The callback argument object passed to the load function.
8996 * @event loadexception
8997 * Fires if an Exception occurs during data retrieval.
8998 * @param {Object} This DataProxy object.
8999 * @param {Object} o The data object.
9000 * @param {Object} arg The callback argument object passed to the load function.
9001 * @param {Object} e The Exception.
9003 loadexception : true
9005 Roo.data.DataProxy.superclass.constructor.call(this);
9008 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9011 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9015 * Ext JS Library 1.1.1
9016 * Copyright(c) 2006-2007, Ext JS, LLC.
9018 * Originally Released Under LGPL - original licence link has changed is not relivant.
9021 * <script type="text/javascript">
9024 * @class Roo.data.MemoryProxy
9025 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9026 * to the Reader when its load method is called.
9028 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9030 Roo.data.MemoryProxy = function(data){
9034 Roo.data.MemoryProxy.superclass.constructor.call(this);
9038 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9040 * Load data from the requested source (in this case an in-memory
9041 * data object passed to the constructor), read the data object into
9042 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9043 * process that block using the passed callback.
9044 * @param {Object} params This parameter is not used by the MemoryProxy class.
9045 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9046 * object into a block of Roo.data.Records.
9047 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9048 * The function must be passed <ul>
9049 * <li>The Record block object</li>
9050 * <li>The "arg" argument from the load function</li>
9051 * <li>A boolean success indicator</li>
9053 * @param {Object} scope The scope in which to call the callback
9054 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9056 load : function(params, reader, callback, scope, arg){
9057 params = params || {};
9060 result = reader.readRecords(this.data);
9062 this.fireEvent("loadexception", this, arg, null, e);
9063 callback.call(scope, null, arg, false);
9066 callback.call(scope, result, arg, true);
9070 update : function(params, records){
9075 * Ext JS Library 1.1.1
9076 * Copyright(c) 2006-2007, Ext JS, LLC.
9078 * Originally Released Under LGPL - original licence link has changed is not relivant.
9081 * <script type="text/javascript">
9084 * @class Roo.data.HttpProxy
9085 * @extends Roo.data.DataProxy
9086 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9087 * configured to reference a certain URL.<br><br>
9089 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9090 * from which the running page was served.<br><br>
9092 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9094 * Be aware that to enable the browser to parse an XML document, the server must set
9095 * the Content-Type header in the HTTP response to "text/xml".
9097 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9098 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9099 * will be used to make the request.
9101 Roo.data.HttpProxy = function(conn){
9102 Roo.data.HttpProxy.superclass.constructor.call(this);
9103 // is conn a conn config or a real conn?
9105 this.useAjax = !conn || !conn.events;
9109 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9110 // thse are take from connection...
9113 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9116 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9117 * extra parameters to each request made by this object. (defaults to undefined)
9120 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9121 * to each request made by this object. (defaults to undefined)
9124 * @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)
9127 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9130 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9136 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9140 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9141 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9142 * a finer-grained basis than the DataProxy events.
9144 getConnection : function(){
9145 return this.useAjax ? Roo.Ajax : this.conn;
9149 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9150 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9151 * process that block using the passed callback.
9152 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9153 * for the request to the remote server.
9154 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9155 * object into a block of Roo.data.Records.
9156 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9157 * The function must be passed <ul>
9158 * <li>The Record block object</li>
9159 * <li>The "arg" argument from the load function</li>
9160 * <li>A boolean success indicator</li>
9162 * @param {Object} scope The scope in which to call the callback
9163 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9165 load : function(params, reader, callback, scope, arg){
9166 if(this.fireEvent("beforeload", this, params) !== false){
9168 params : params || {},
9170 callback : callback,
9175 callback : this.loadResponse,
9179 Roo.applyIf(o, this.conn);
9180 if(this.activeRequest){
9181 Roo.Ajax.abort(this.activeRequest);
9183 this.activeRequest = Roo.Ajax.request(o);
9185 this.conn.request(o);
9188 callback.call(scope||this, null, arg, false);
9193 loadResponse : function(o, success, response){
9194 delete this.activeRequest;
9196 this.fireEvent("loadexception", this, o, response);
9197 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9202 result = o.reader.read(response);
9204 this.fireEvent("loadexception", this, o, response, e);
9205 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9209 this.fireEvent("load", this, o, o.request.arg);
9210 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9214 update : function(dataSet){
9219 updateResponse : function(dataSet){
9224 * Ext JS Library 1.1.1
9225 * Copyright(c) 2006-2007, Ext JS, LLC.
9227 * Originally Released Under LGPL - original licence link has changed is not relivant.
9230 * <script type="text/javascript">
9234 * @class Roo.data.ScriptTagProxy
9235 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9236 * other than the originating domain of the running page.<br><br>
9238 * <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
9239 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9241 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9242 * source code that is used as the source inside a <script> tag.<br><br>
9244 * In order for the browser to process the returned data, the server must wrap the data object
9245 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9246 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9247 * depending on whether the callback name was passed:
9250 boolean scriptTag = false;
9251 String cb = request.getParameter("callback");
9254 response.setContentType("text/javascript");
9256 response.setContentType("application/x-json");
9258 Writer out = response.getWriter();
9260 out.write(cb + "(");
9262 out.print(dataBlock.toJsonString());
9269 * @param {Object} config A configuration object.
9271 Roo.data.ScriptTagProxy = function(config){
9272 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9273 Roo.apply(this, config);
9274 this.head = document.getElementsByTagName("head")[0];
9277 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9279 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9281 * @cfg {String} url The URL from which to request the data object.
9284 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9288 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9289 * the server the name of the callback function set up by the load call to process the returned data object.
9290 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9291 * javascript output which calls this named function passing the data object as its only parameter.
9293 callbackParam : "callback",
9295 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9296 * name to the request.
9301 * Load data from the configured URL, read the data object into
9302 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9303 * process that block using the passed callback.
9304 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9305 * for the request to the remote server.
9306 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9307 * object into a block of Roo.data.Records.
9308 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9309 * The function must be passed <ul>
9310 * <li>The Record block object</li>
9311 * <li>The "arg" argument from the load function</li>
9312 * <li>A boolean success indicator</li>
9314 * @param {Object} scope The scope in which to call the callback
9315 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9317 load : function(params, reader, callback, scope, arg){
9318 if(this.fireEvent("beforeload", this, params) !== false){
9320 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9323 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9325 url += "&_dc=" + (new Date().getTime());
9327 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9330 cb : "stcCallback"+transId,
9331 scriptId : "stcScript"+transId,
9335 callback : callback,
9341 window[trans.cb] = function(o){
9342 conn.handleResponse(o, trans);
9345 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9347 if(this.autoAbort !== false){
9351 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9353 var script = document.createElement("script");
9354 script.setAttribute("src", url);
9355 script.setAttribute("type", "text/javascript");
9356 script.setAttribute("id", trans.scriptId);
9357 this.head.appendChild(script);
9361 callback.call(scope||this, null, arg, false);
9366 isLoading : function(){
9367 return this.trans ? true : false;
9371 * Abort the current server request.
9374 if(this.isLoading()){
9375 this.destroyTrans(this.trans);
9380 destroyTrans : function(trans, isLoaded){
9381 this.head.removeChild(document.getElementById(trans.scriptId));
9382 clearTimeout(trans.timeoutId);
9384 window[trans.cb] = undefined;
9386 delete window[trans.cb];
9389 // if hasn't been loaded, wait for load to remove it to prevent script error
9390 window[trans.cb] = function(){
9391 window[trans.cb] = undefined;
9393 delete window[trans.cb];
9400 handleResponse : function(o, trans){
9402 this.destroyTrans(trans, true);
9405 result = trans.reader.readRecords(o);
9407 this.fireEvent("loadexception", this, o, trans.arg, e);
9408 trans.callback.call(trans.scope||window, null, trans.arg, false);
9411 this.fireEvent("load", this, o, trans.arg);
9412 trans.callback.call(trans.scope||window, result, trans.arg, true);
9416 handleFailure : function(trans){
9418 this.destroyTrans(trans, false);
9419 this.fireEvent("loadexception", this, null, trans.arg);
9420 trans.callback.call(trans.scope||window, null, trans.arg, false);
9424 * Ext JS Library 1.1.1
9425 * Copyright(c) 2006-2007, Ext JS, LLC.
9427 * Originally Released Under LGPL - original licence link has changed is not relivant.
9430 * <script type="text/javascript">
9434 * @class Roo.data.JsonReader
9435 * @extends Roo.data.DataReader
9436 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9437 * based on mappings in a provided Roo.data.Record constructor.
9439 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9440 * in the reply previously.
9445 var RecordDef = Roo.data.Record.create([
9446 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9447 {name: 'occupation'} // This field will use "occupation" as the mapping.
9449 var myReader = new Roo.data.JsonReader({
9450 totalProperty: "results", // The property which contains the total dataset size (optional)
9451 root: "rows", // The property which contains an Array of row objects
9452 id: "id" // The property within each row object that provides an ID for the record (optional)
9456 * This would consume a JSON file like this:
9458 { 'results': 2, 'rows': [
9459 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9460 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9463 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9464 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9465 * paged from the remote server.
9466 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9467 * @cfg {String} root name of the property which contains the Array of row objects.
9468 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9470 * Create a new JsonReader
9471 * @param {Object} meta Metadata configuration options
9472 * @param {Object} recordType Either an Array of field definition objects,
9473 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9475 Roo.data.JsonReader = function(meta, recordType){
9478 // set some defaults:
9480 totalProperty: 'total',
9481 successProperty : 'success',
9486 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9488 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9491 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9492 * Used by Store query builder to append _requestMeta to params.
9495 metaFromRemote : false,
9497 * This method is only used by a DataProxy which has retrieved data from a remote server.
9498 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9499 * @return {Object} data A data block which is used by an Roo.data.Store object as
9500 * a cache of Roo.data.Records.
9502 read : function(response){
9503 var json = response.responseText;
9505 var o = /* eval:var:o */ eval("("+json+")");
9507 throw {message: "JsonReader.read: Json object not found"};
9513 this.metaFromRemote = true;
9514 this.meta = o.metaData;
9515 this.recordType = Roo.data.Record.create(o.metaData.fields);
9516 this.onMetaChange(this.meta, this.recordType, o);
9518 return this.readRecords(o);
9521 // private function a store will implement
9522 onMetaChange : function(meta, recordType, o){
9529 simpleAccess: function(obj, subsc) {
9536 getJsonAccessor: function(){
9538 return function(expr) {
9540 return(re.test(expr))
9541 ? new Function("obj", "return obj." + expr)
9551 * Create a data block containing Roo.data.Records from an XML document.
9552 * @param {Object} o An object which contains an Array of row objects in the property specified
9553 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9554 * which contains the total size of the dataset.
9555 * @return {Object} data A data block which is used by an Roo.data.Store object as
9556 * a cache of Roo.data.Records.
9558 readRecords : function(o){
9560 * After any data loads, the raw JSON data is available for further custom processing.
9564 var s = this.meta, Record = this.recordType,
9565 f = Record.prototype.fields, fi = f.items, fl = f.length;
9567 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9569 if(s.totalProperty) {
9570 this.getTotal = this.getJsonAccessor(s.totalProperty);
9572 if(s.successProperty) {
9573 this.getSuccess = this.getJsonAccessor(s.successProperty);
9575 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9577 var g = this.getJsonAccessor(s.id);
9578 this.getId = function(rec) {
9580 return (r === undefined || r === "") ? null : r;
9583 this.getId = function(){return null;};
9586 for(var jj = 0; jj < fl; jj++){
9588 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9589 this.ef[jj] = this.getJsonAccessor(map);
9593 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9594 if(s.totalProperty){
9595 var vt = parseInt(this.getTotal(o), 10);
9600 if(s.successProperty){
9601 var vs = this.getSuccess(o);
9602 if(vs === false || vs === 'false'){
9607 for(var i = 0; i < c; i++){
9610 var id = this.getId(n);
9611 for(var j = 0; j < fl; j++){
9613 var v = this.ef[j](n);
9615 Roo.log('missing convert for ' + f.name);
9619 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9621 var record = new Record(values, id);
9623 records[i] = record;
9629 totalRecords : totalRecords
9634 * Ext JS Library 1.1.1
9635 * Copyright(c) 2006-2007, Ext JS, LLC.
9637 * Originally Released Under LGPL - original licence link has changed is not relivant.
9640 * <script type="text/javascript">
9644 * @class Roo.data.ArrayReader
9645 * @extends Roo.data.DataReader
9646 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9647 * Each element of that Array represents a row of data fields. The
9648 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9649 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9653 var RecordDef = Roo.data.Record.create([
9654 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9655 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9657 var myReader = new Roo.data.ArrayReader({
9658 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9662 * This would consume an Array like this:
9664 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9666 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9668 * Create a new JsonReader
9669 * @param {Object} meta Metadata configuration options.
9670 * @param {Object} recordType Either an Array of field definition objects
9671 * as specified to {@link Roo.data.Record#create},
9672 * or an {@link Roo.data.Record} object
9673 * created using {@link Roo.data.Record#create}.
9675 Roo.data.ArrayReader = function(meta, recordType){
9676 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9679 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9681 * Create a data block containing Roo.data.Records from an XML document.
9682 * @param {Object} o An Array of row objects which represents the dataset.
9683 * @return {Object} data A data block which is used by an Roo.data.Store object as
9684 * a cache of Roo.data.Records.
9686 readRecords : function(o){
9687 var sid = this.meta ? this.meta.id : null;
9688 var recordType = this.recordType, fields = recordType.prototype.fields;
9691 for(var i = 0; i < root.length; i++){
9694 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9695 for(var j = 0, jlen = fields.length; j < jlen; j++){
9696 var f = fields.items[j];
9697 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9698 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9702 var record = new recordType(values, id);
9704 records[records.length] = record;
9708 totalRecords : records.length
9717 * @class Roo.bootstrap.ComboBox
9718 * @extends Roo.bootstrap.TriggerField
9719 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9720 * @cfg {Boolean} append (true|false) default false
9721 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9723 * Create a new ComboBox.
9724 * @param {Object} config Configuration options
9726 Roo.bootstrap.ComboBox = function(config){
9727 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9731 * Fires when the dropdown list is expanded
9732 * @param {Roo.bootstrap.ComboBox} combo This combo box
9737 * Fires when the dropdown list is collapsed
9738 * @param {Roo.bootstrap.ComboBox} combo This combo box
9742 * @event beforeselect
9743 * Fires before a list item is selected. Return false to cancel the selection.
9744 * @param {Roo.bootstrap.ComboBox} combo This combo box
9745 * @param {Roo.data.Record} record The data record returned from the underlying store
9746 * @param {Number} index The index of the selected item in the dropdown list
9748 'beforeselect' : true,
9751 * Fires when a list item is selected
9752 * @param {Roo.bootstrap.ComboBox} combo This combo box
9753 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9754 * @param {Number} index The index of the selected item in the dropdown list
9758 * @event beforequery
9759 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9760 * The event object passed has these properties:
9761 * @param {Roo.bootstrap.ComboBox} combo This combo box
9762 * @param {String} query The query
9763 * @param {Boolean} forceAll true to force "all" query
9764 * @param {Boolean} cancel true to cancel the query
9765 * @param {Object} e The query event object
9767 'beforequery': true,
9770 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9771 * @param {Roo.bootstrap.ComboBox} combo This combo box
9776 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9777 * @param {Roo.bootstrap.ComboBox} combo This combo box
9778 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9783 * Fires when the remove value from the combobox array
9784 * @param {Roo.bootstrap.ComboBox} combo This combo box
9791 this.selectedIndex = -1;
9792 if(this.mode == 'local'){
9793 if(config.queryDelay === undefined){
9794 this.queryDelay = 10;
9796 if(config.minChars === undefined){
9802 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9805 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9806 * rendering into an Roo.Editor, defaults to false)
9809 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9810 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9813 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9816 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9817 * the dropdown list (defaults to undefined, with no header element)
9821 * @cfg {String/Roo.Template} tpl The template to use to render the output
9825 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9827 listWidth: undefined,
9829 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9830 * mode = 'remote' or 'text' if mode = 'local')
9832 displayField: undefined,
9834 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9835 * mode = 'remote' or 'value' if mode = 'local').
9836 * Note: use of a valueField requires the user make a selection
9837 * in order for a value to be mapped.
9839 valueField: undefined,
9843 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9844 * field's data value (defaults to the underlying DOM element's name)
9846 hiddenName: undefined,
9848 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9852 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9854 selectedClass: 'active',
9857 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9861 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9862 * anchor positions (defaults to 'tl-bl')
9864 listAlign: 'tl-bl?',
9866 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9870 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9871 * query specified by the allQuery config option (defaults to 'query')
9873 triggerAction: 'query',
9875 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9876 * (defaults to 4, does not apply if editable = false)
9880 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9881 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9885 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9886 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9890 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9891 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9895 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9896 * when editable = true (defaults to false)
9898 selectOnFocus:false,
9900 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9902 queryParam: 'query',
9904 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9905 * when mode = 'remote' (defaults to 'Loading...')
9907 loadingText: 'Loading...',
9909 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9913 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9917 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9918 * traditional select (defaults to true)
9922 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9926 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9930 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9931 * listWidth has a higher value)
9935 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9936 * allow the user to set arbitrary text into the field (defaults to false)
9938 forceSelection:false,
9940 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9941 * if typeAhead = true (defaults to 250)
9943 typeAheadDelay : 250,
9945 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9946 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9948 valueNotFoundText : undefined,
9950 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9955 * @cfg {Boolean} disableClear Disable showing of clear button.
9957 disableClear : false,
9959 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9961 alwaysQuery : false,
9964 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9979 // element that contains real text value.. (when hidden is used..)
9982 initEvents: function(){
9985 throw "can not find store for combo";
9987 this.store = Roo.factory(this.store, Roo.data);
9991 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9994 if(this.hiddenName){
9996 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9998 this.hiddenField.dom.value =
9999 this.hiddenValue !== undefined ? this.hiddenValue :
10000 this.value !== undefined ? this.value : '';
10002 // prevent input submission
10003 this.el.dom.removeAttribute('name');
10004 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10009 // this.el.dom.setAttribute('autocomplete', 'off');
10012 var cls = 'x-combo-list';
10013 this.list = this.el.select('ul.dropdown-menu',true).first();
10015 //this.list = new Roo.Layer({
10016 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10019 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
10020 this.list.setWidth(lw);
10022 this.list.on('mouseover', this.onViewOver, this);
10023 this.list.on('mousemove', this.onViewMove, this);
10025 this.list.on('scroll', this.onViewScroll, this);
10028 this.list.swallowEvent('mousewheel');
10029 this.assetHeight = 0;
10032 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10033 this.assetHeight += this.header.getHeight();
10036 this.innerList = this.list.createChild({cls:cls+'-inner'});
10037 this.innerList.on('mouseover', this.onViewOver, this);
10038 this.innerList.on('mousemove', this.onViewMove, this);
10039 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10041 if(this.allowBlank && !this.pageSize && !this.disableClear){
10042 this.footer = this.list.createChild({cls:cls+'-ft'});
10043 this.pageTb = new Roo.Toolbar(this.footer);
10047 this.footer = this.list.createChild({cls:cls+'-ft'});
10048 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10049 {pageSize: this.pageSize});
10053 if (this.pageTb && this.allowBlank && !this.disableClear) {
10055 this.pageTb.add(new Roo.Toolbar.Fill(), {
10056 cls: 'x-btn-icon x-btn-clear',
10058 handler: function()
10061 _this.clearValue();
10062 _this.onSelect(false, -1);
10067 this.assetHeight += this.footer.getHeight();
10072 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10075 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10076 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10078 //this.view.wrapEl.setDisplayed(false);
10079 this.view.on('click', this.onViewClick, this);
10083 this.store.on('beforeload', this.onBeforeLoad, this);
10084 this.store.on('load', this.onLoad, this);
10085 this.store.on('loadexception', this.onLoadException, this);
10087 if(this.resizable){
10088 this.resizer = new Roo.Resizable(this.list, {
10089 pinned:true, handles:'se'
10091 this.resizer.on('resize', function(r, w, h){
10092 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10093 this.listWidth = w;
10094 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10095 this.restrictHeight();
10097 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10100 if(!this.editable){
10101 this.editable = true;
10102 this.setEditable(false);
10107 if (typeof(this.events.add.listeners) != 'undefined') {
10109 this.addicon = this.wrap.createChild(
10110 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10112 this.addicon.on('click', function(e) {
10113 this.fireEvent('add', this);
10116 if (typeof(this.events.edit.listeners) != 'undefined') {
10118 this.editicon = this.wrap.createChild(
10119 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10120 if (this.addicon) {
10121 this.editicon.setStyle('margin-left', '40px');
10123 this.editicon.on('click', function(e) {
10125 // we fire even if inothing is selected..
10126 this.fireEvent('edit', this, this.lastData );
10132 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10133 "up" : function(e){
10134 this.inKeyMode = true;
10138 "down" : function(e){
10139 if(!this.isExpanded()){
10140 this.onTriggerClick();
10142 this.inKeyMode = true;
10147 "enter" : function(e){
10148 // this.onViewClick();
10152 if(this.fireEvent("specialkey", this, e)){
10153 this.onViewClick(false);
10159 "esc" : function(e){
10163 "tab" : function(e){
10166 if(this.fireEvent("specialkey", this, e)){
10167 this.onViewClick(false);
10175 doRelay : function(foo, bar, hname){
10176 if(hname == 'down' || this.scope.isExpanded()){
10177 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10186 this.queryDelay = Math.max(this.queryDelay || 10,
10187 this.mode == 'local' ? 10 : 250);
10190 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10192 if(this.typeAhead){
10193 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10195 if(this.editable !== false){
10196 this.inputEl().on("keyup", this.onKeyUp, this);
10198 if(this.forceSelection){
10199 this.inputEl().on('blur', this.doForce, this);
10203 this.choices = this.el.select('ul.select2-choices', true).first();
10204 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10208 onDestroy : function(){
10210 this.view.setStore(null);
10211 this.view.el.removeAllListeners();
10212 this.view.el.remove();
10213 this.view.purgeListeners();
10216 this.list.dom.innerHTML = '';
10219 this.store.un('beforeload', this.onBeforeLoad, this);
10220 this.store.un('load', this.onLoad, this);
10221 this.store.un('loadexception', this.onLoadException, this);
10223 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10227 fireKey : function(e){
10228 if(e.isNavKeyPress() && !this.list.isVisible()){
10229 this.fireEvent("specialkey", this, e);
10234 onResize: function(w, h){
10235 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10237 // if(typeof w != 'number'){
10238 // // we do not handle it!?!?
10241 // var tw = this.trigger.getWidth();
10242 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10243 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10245 // this.inputEl().setWidth( this.adjustWidth('input', x));
10247 // //this.trigger.setStyle('left', x+'px');
10249 // if(this.list && this.listWidth === undefined){
10250 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10251 // this.list.setWidth(lw);
10252 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10260 * Allow or prevent the user from directly editing the field text. If false is passed,
10261 * the user will only be able to select from the items defined in the dropdown list. This method
10262 * is the runtime equivalent of setting the 'editable' config option at config time.
10263 * @param {Boolean} value True to allow the user to directly edit the field text
10265 setEditable : function(value){
10266 if(value == this.editable){
10269 this.editable = value;
10271 this.inputEl().dom.setAttribute('readOnly', true);
10272 this.inputEl().on('mousedown', this.onTriggerClick, this);
10273 this.inputEl().addClass('x-combo-noedit');
10275 this.inputEl().dom.setAttribute('readOnly', false);
10276 this.inputEl().un('mousedown', this.onTriggerClick, this);
10277 this.inputEl().removeClass('x-combo-noedit');
10283 onBeforeLoad : function(combo,opts){
10284 if(!this.hasFocus){
10288 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10290 this.restrictHeight();
10291 this.selectedIndex = -1;
10295 onLoad : function(){
10297 this.hasQuery = false;
10299 if(!this.hasFocus){
10303 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10304 this.loading.hide();
10307 if(this.store.getCount() > 0){
10309 this.restrictHeight();
10310 if(this.lastQuery == this.allQuery){
10312 this.inputEl().dom.select();
10314 if(!this.selectByValue(this.value, true) && this.autoFocus){
10315 this.select(0, true);
10318 if(this.autoFocus){
10321 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10322 this.taTask.delay(this.typeAheadDelay);
10326 this.onEmptyResults();
10332 onLoadException : function()
10334 this.hasQuery = false;
10336 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10337 this.loading.hide();
10341 Roo.log(this.store.reader.jsonData);
10342 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10344 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10350 onTypeAhead : function(){
10351 if(this.store.getCount() > 0){
10352 var r = this.store.getAt(0);
10353 var newValue = r.data[this.displayField];
10354 var len = newValue.length;
10355 var selStart = this.getRawValue().length;
10357 if(selStart != len){
10358 this.setRawValue(newValue);
10359 this.selectText(selStart, newValue.length);
10365 onSelect : function(record, index){
10367 if(this.fireEvent('beforeselect', this, record, index) !== false){
10369 this.setFromData(index > -1 ? record.data : false);
10372 this.fireEvent('select', this, record, index);
10377 * Returns the currently selected field value or empty string if no value is set.
10378 * @return {String} value The selected value
10380 getValue : function(){
10383 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10386 if(this.valueField){
10387 return typeof this.value != 'undefined' ? this.value : '';
10389 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10394 * Clears any text/value currently set in the field
10396 clearValue : function(){
10397 if(this.hiddenField){
10398 this.hiddenField.dom.value = '';
10401 this.setRawValue('');
10402 this.lastSelectionText = '';
10407 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10408 * will be displayed in the field. If the value does not match the data value of an existing item,
10409 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10410 * Otherwise the field will be blank (although the value will still be set).
10411 * @param {String} value The value to match
10413 setValue : function(v){
10420 if(this.valueField){
10421 var r = this.findRecord(this.valueField, v);
10423 text = r.data[this.displayField];
10424 }else if(this.valueNotFoundText !== undefined){
10425 text = this.valueNotFoundText;
10428 this.lastSelectionText = text;
10429 if(this.hiddenField){
10430 this.hiddenField.dom.value = v;
10432 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10436 * @property {Object} the last set data for the element
10441 * Sets the value of the field based on a object which is related to the record format for the store.
10442 * @param {Object} value the value to set as. or false on reset?
10444 setFromData : function(o){
10451 var dv = ''; // display value
10452 var vv = ''; // value value..
10454 if (this.displayField) {
10455 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10457 // this is an error condition!!!
10458 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10461 if(this.valueField){
10462 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10465 if(this.hiddenField){
10466 this.hiddenField.dom.value = vv;
10468 this.lastSelectionText = dv;
10469 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10473 // no hidden field.. - we store the value in 'value', but still display
10474 // display field!!!!
10475 this.lastSelectionText = dv;
10476 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10482 reset : function(){
10483 // overridden so that last data is reset..
10484 this.setValue(this.originalValue);
10485 this.clearInvalid();
10486 this.lastData = false;
10488 this.view.clearSelections();
10492 findRecord : function(prop, value){
10494 if(this.store.getCount() > 0){
10495 this.store.each(function(r){
10496 if(r.data[prop] == value){
10506 getName: function()
10508 // returns hidden if it's set..
10509 if (!this.rendered) {return ''};
10510 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10514 onViewMove : function(e, t){
10515 this.inKeyMode = false;
10519 onViewOver : function(e, t){
10520 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10523 var item = this.view.findItemFromChild(t);
10525 var index = this.view.indexOf(item);
10526 this.select(index, false);
10531 onViewClick : function(doFocus)
10533 var index = this.view.getSelectedIndexes()[0];
10534 var r = this.store.getAt(index);
10536 this.onSelect(r, index);
10538 if(doFocus !== false && !this.blockFocus){
10539 this.inputEl().focus();
10544 restrictHeight : function(){
10545 //this.innerList.dom.style.height = '';
10546 //var inner = this.innerList.dom;
10547 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10548 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10549 //this.list.beginUpdate();
10550 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10551 this.list.alignTo(this.inputEl(), this.listAlign);
10552 //this.list.endUpdate();
10556 onEmptyResults : function(){
10561 * Returns true if the dropdown list is expanded, else false.
10563 isExpanded : function(){
10564 return this.list.isVisible();
10568 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
10569 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10570 * @param {String} value The data value of the item to select
10571 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10572 * selected item if it is not currently in view (defaults to true)
10573 * @return {Boolean} True if the value matched an item in the list, else false
10575 selectByValue : function(v, scrollIntoView){
10576 if(v !== undefined && v !== null){
10577 var r = this.findRecord(this.valueField || this.displayField, v);
10579 this.select(this.store.indexOf(r), scrollIntoView);
10587 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
10588 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10589 * @param {Number} index The zero-based index of the list item to select
10590 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10591 * selected item if it is not currently in view (defaults to true)
10593 select : function(index, scrollIntoView){
10594 this.selectedIndex = index;
10595 this.view.select(index);
10596 if(scrollIntoView !== false){
10597 var el = this.view.getNode(index);
10599 //this.innerList.scrollChildIntoView(el, false);
10606 selectNext : function(){
10607 var ct = this.store.getCount();
10609 if(this.selectedIndex == -1){
10611 }else if(this.selectedIndex < ct-1){
10612 this.select(this.selectedIndex+1);
10618 selectPrev : function(){
10619 var ct = this.store.getCount();
10621 if(this.selectedIndex == -1){
10623 }else if(this.selectedIndex != 0){
10624 this.select(this.selectedIndex-1);
10630 onKeyUp : function(e){
10631 if(this.editable !== false && !e.isSpecialKey()){
10632 this.lastKey = e.getKey();
10633 this.dqTask.delay(this.queryDelay);
10638 validateBlur : function(){
10639 return !this.list || !this.list.isVisible();
10643 initQuery : function(){
10644 this.doQuery(this.getRawValue());
10648 doForce : function(){
10649 if(this.inputEl().dom.value.length > 0){
10650 this.inputEl().dom.value =
10651 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10657 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10658 * query allowing the query action to be canceled if needed.
10659 * @param {String} query The SQL query to execute
10660 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10661 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10662 * saved in the current store (defaults to false)
10664 doQuery : function(q, forceAll){
10666 if(q === undefined || q === null){
10671 forceAll: forceAll,
10675 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10680 forceAll = qe.forceAll;
10681 if(forceAll === true || (q.length >= this.minChars)){
10683 this.hasQuery = true;
10685 if(this.lastQuery != q || this.alwaysQuery){
10686 this.lastQuery = q;
10687 if(this.mode == 'local'){
10688 this.selectedIndex = -1;
10690 this.store.clearFilter();
10692 this.store.filter(this.displayField, q);
10696 this.store.baseParams[this.queryParam] = q;
10698 var options = {params : this.getParams(q)};
10701 options.add = true;
10702 options.params.start = this.page * this.pageSize;
10705 this.store.load(options);
10707 * this code will make the page width larger, at the beginning, the list not align correctly,
10708 * we should expand the list on onLoad
10709 * so command out it
10714 this.selectedIndex = -1;
10719 this.loadNext = false;
10723 getParams : function(q){
10725 //p[this.queryParam] = q;
10729 p.limit = this.pageSize;
10735 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10737 collapse : function(){
10738 if(!this.isExpanded()){
10743 Roo.get(document).un('mousedown', this.collapseIf, this);
10744 Roo.get(document).un('mousewheel', this.collapseIf, this);
10745 if (!this.editable) {
10746 Roo.get(document).un('keydown', this.listKeyPress, this);
10748 this.fireEvent('collapse', this);
10752 collapseIf : function(e){
10753 var in_combo = e.within(this.el);
10754 var in_list = e.within(this.list);
10756 if (in_combo || in_list) {
10757 //e.stopPropagation();
10766 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10768 expand : function(){
10770 if(this.isExpanded() || !this.hasFocus){
10774 this.list.alignTo(this.inputEl(), this.listAlign);
10776 Roo.get(document).on('mousedown', this.collapseIf, this);
10777 Roo.get(document).on('mousewheel', this.collapseIf, this);
10778 if (!this.editable) {
10779 Roo.get(document).on('keydown', this.listKeyPress, this);
10782 this.fireEvent('expand', this);
10786 // Implements the default empty TriggerField.onTriggerClick function
10787 onTriggerClick : function()
10789 Roo.log('trigger click');
10796 this.loadNext = false;
10798 if(this.isExpanded()){
10800 if (!this.blockFocus) {
10801 this.inputEl().focus();
10805 this.hasFocus = true;
10806 if(this.triggerAction == 'all') {
10807 this.doQuery(this.allQuery, true);
10809 this.doQuery(this.getRawValue());
10811 if (!this.blockFocus) {
10812 this.inputEl().focus();
10816 listKeyPress : function(e)
10818 //Roo.log('listkeypress');
10819 // scroll to first matching element based on key pres..
10820 if (e.isSpecialKey()) {
10823 var k = String.fromCharCode(e.getKey()).toUpperCase();
10826 var csel = this.view.getSelectedNodes();
10827 var cselitem = false;
10829 var ix = this.view.indexOf(csel[0]);
10830 cselitem = this.store.getAt(ix);
10831 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10837 this.store.each(function(v) {
10839 // start at existing selection.
10840 if (cselitem.id == v.id) {
10846 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10847 match = this.store.indexOf(v);
10853 if (match === false) {
10854 return true; // no more action?
10857 this.view.select(match);
10858 var sn = Roo.get(this.view.getSelectedNodes()[0])
10859 //sn.scrollIntoView(sn.dom.parentNode, false);
10862 onViewScroll : function(e, t){
10864 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10868 this.hasQuery = true;
10870 this.loading = this.list.select('.loading', true).first();
10872 if(this.loading === null){
10873 this.list.createChild({
10875 cls: 'loading select2-more-results select2-active',
10876 html: 'Loading more results...'
10879 this.loading = this.list.select('.loading', true).first();
10881 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10883 this.loading.hide();
10886 this.loading.show();
10891 this.loadNext = true;
10893 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10898 addItem : function(o)
10900 var dv = ''; // display value
10902 if (this.displayField) {
10903 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10905 // this is an error condition!!!
10906 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10913 var choice = this.choices.createChild({
10915 cls: 'select2-search-choice',
10924 cls: 'select2-search-choice-close',
10929 }, this.searchField);
10931 var close = choice.select('a.select2-search-choice-close', true).first()
10933 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10940 this.inputEl().dom.value = '';
10944 onRemoveItem : function(e, _self, o)
10946 e.preventDefault();
10947 var index = this.item.indexOf(o.data) * 1;
10950 Roo.log('not this item?!');
10954 this.item.splice(index, 1);
10959 this.fireEvent('remove', this, e);
10963 syncValue : function()
10965 if(!this.item.length){
10972 Roo.each(this.item, function(i){
10973 if(_this.valueField){
10974 value.push(i[_this.valueField]);
10981 this.value = value.join(',');
10983 if(this.hiddenField){
10984 this.hiddenField.dom.value = this.value;
10988 clearItem : function()
10990 if(!this.multiple){
10996 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11006 * @cfg {Boolean} grow
11010 * @cfg {Number} growMin
11014 * @cfg {Number} growMax
11024 * Ext JS Library 1.1.1
11025 * Copyright(c) 2006-2007, Ext JS, LLC.
11027 * Originally Released Under LGPL - original licence link has changed is not relivant.
11030 * <script type="text/javascript">
11035 * @extends Roo.util.Observable
11036 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11037 * This class also supports single and multi selection modes. <br>
11038 * Create a data model bound view:
11040 var store = new Roo.data.Store(...);
11042 var view = new Roo.View({
11044 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11046 singleSelect: true,
11047 selectedClass: "ydataview-selected",
11051 // listen for node click?
11052 view.on("click", function(vw, index, node, e){
11053 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11057 dataModel.load("foobar.xml");
11059 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11061 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11062 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11064 * Note: old style constructor is still suported (container, template, config)
11067 * Create a new View
11068 * @param {Object} config The config object
11071 Roo.View = function(config, depreciated_tpl, depreciated_config){
11073 if (typeof(depreciated_tpl) == 'undefined') {
11074 // new way.. - universal constructor.
11075 Roo.apply(this, config);
11076 this.el = Roo.get(this.el);
11079 this.el = Roo.get(config);
11080 this.tpl = depreciated_tpl;
11081 Roo.apply(this, depreciated_config);
11083 this.wrapEl = this.el.wrap().wrap();
11084 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11087 if(typeof(this.tpl) == "string"){
11088 this.tpl = new Roo.Template(this.tpl);
11090 // support xtype ctors..
11091 this.tpl = new Roo.factory(this.tpl, Roo);
11095 this.tpl.compile();
11103 * @event beforeclick
11104 * Fires before a click is processed. Returns false to cancel the default action.
11105 * @param {Roo.View} this
11106 * @param {Number} index The index of the target node
11107 * @param {HTMLElement} node The target node
11108 * @param {Roo.EventObject} e The raw event object
11110 "beforeclick" : true,
11113 * Fires when a template node is clicked.
11114 * @param {Roo.View} this
11115 * @param {Number} index The index of the target node
11116 * @param {HTMLElement} node The target node
11117 * @param {Roo.EventObject} e The raw event object
11122 * Fires when a template node is double clicked.
11123 * @param {Roo.View} this
11124 * @param {Number} index The index of the target node
11125 * @param {HTMLElement} node The target node
11126 * @param {Roo.EventObject} e The raw event object
11130 * @event contextmenu
11131 * Fires when a template node is right clicked.
11132 * @param {Roo.View} this
11133 * @param {Number} index The index of the target node
11134 * @param {HTMLElement} node The target node
11135 * @param {Roo.EventObject} e The raw event object
11137 "contextmenu" : true,
11139 * @event selectionchange
11140 * Fires when the selected nodes change.
11141 * @param {Roo.View} this
11142 * @param {Array} selections Array of the selected nodes
11144 "selectionchange" : true,
11147 * @event beforeselect
11148 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11149 * @param {Roo.View} this
11150 * @param {HTMLElement} node The node to be selected
11151 * @param {Array} selections Array of currently selected nodes
11153 "beforeselect" : true,
11155 * @event preparedata
11156 * Fires on every row to render, to allow you to change the data.
11157 * @param {Roo.View} this
11158 * @param {Object} data to be rendered (change this)
11160 "preparedata" : true
11168 "click": this.onClick,
11169 "dblclick": this.onDblClick,
11170 "contextmenu": this.onContextMenu,
11174 this.selections = [];
11176 this.cmp = new Roo.CompositeElementLite([]);
11178 this.store = Roo.factory(this.store, Roo.data);
11179 this.setStore(this.store, true);
11182 if ( this.footer && this.footer.xtype) {
11184 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11186 this.footer.dataSource = this.store
11187 this.footer.container = fctr;
11188 this.footer = Roo.factory(this.footer, Roo);
11189 fctr.insertFirst(this.el);
11191 // this is a bit insane - as the paging toolbar seems to detach the el..
11192 // dom.parentNode.parentNode.parentNode
11193 // they get detached?
11197 Roo.View.superclass.constructor.call(this);
11202 Roo.extend(Roo.View, Roo.util.Observable, {
11205 * @cfg {Roo.data.Store} store Data store to load data from.
11210 * @cfg {String|Roo.Element} el The container element.
11215 * @cfg {String|Roo.Template} tpl The template used by this View
11219 * @cfg {String} dataName the named area of the template to use as the data area
11220 * Works with domtemplates roo-name="name"
11224 * @cfg {String} selectedClass The css class to add to selected nodes
11226 selectedClass : "x-view-selected",
11228 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11233 * @cfg {String} text to display on mask (default Loading)
11237 * @cfg {Boolean} multiSelect Allow multiple selection
11239 multiSelect : false,
11241 * @cfg {Boolean} singleSelect Allow single selection
11243 singleSelect: false,
11246 * @cfg {Boolean} toggleSelect - selecting
11248 toggleSelect : false,
11251 * Returns the element this view is bound to.
11252 * @return {Roo.Element}
11254 getEl : function(){
11255 return this.wrapEl;
11261 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11263 refresh : function(){
11264 Roo.log('refresh');
11267 // if we are using something like 'domtemplate', then
11268 // the what gets used is:
11269 // t.applySubtemplate(NAME, data, wrapping data..)
11270 // the outer template then get' applied with
11271 // the store 'extra data'
11272 // and the body get's added to the
11273 // roo-name="data" node?
11274 // <span class='roo-tpl-{name}'></span> ?????
11278 this.clearSelections();
11279 this.el.update("");
11281 var records = this.store.getRange();
11282 if(records.length < 1) {
11284 // is this valid?? = should it render a template??
11286 this.el.update(this.emptyText);
11290 if (this.dataName) {
11291 this.el.update(t.apply(this.store.meta)); //????
11292 el = this.el.child('.roo-tpl-' + this.dataName);
11295 for(var i = 0, len = records.length; i < len; i++){
11296 var data = this.prepareData(records[i].data, i, records[i]);
11297 this.fireEvent("preparedata", this, data, i, records[i]);
11298 html[html.length] = Roo.util.Format.trim(
11300 t.applySubtemplate(this.dataName, data, this.store.meta) :
11307 el.update(html.join(""));
11308 this.nodes = el.dom.childNodes;
11309 this.updateIndexes(0);
11314 * Function to override to reformat the data that is sent to
11315 * the template for each node.
11316 * DEPRICATED - use the preparedata event handler.
11317 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11318 * a JSON object for an UpdateManager bound view).
11320 prepareData : function(data, index, record)
11322 this.fireEvent("preparedata", this, data, index, record);
11326 onUpdate : function(ds, record){
11327 Roo.log('on update');
11328 this.clearSelections();
11329 var index = this.store.indexOf(record);
11330 var n = this.nodes[index];
11331 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11332 n.parentNode.removeChild(n);
11333 this.updateIndexes(index, index);
11339 onAdd : function(ds, records, index)
11341 Roo.log(['on Add', ds, records, index] );
11342 this.clearSelections();
11343 if(this.nodes.length == 0){
11347 var n = this.nodes[index];
11348 for(var i = 0, len = records.length; i < len; i++){
11349 var d = this.prepareData(records[i].data, i, records[i]);
11351 this.tpl.insertBefore(n, d);
11354 this.tpl.append(this.el, d);
11357 this.updateIndexes(index);
11360 onRemove : function(ds, record, index){
11361 Roo.log('onRemove');
11362 this.clearSelections();
11363 var el = this.dataName ?
11364 this.el.child('.roo-tpl-' + this.dataName) :
11367 el.dom.removeChild(this.nodes[index]);
11368 this.updateIndexes(index);
11372 * Refresh an individual node.
11373 * @param {Number} index
11375 refreshNode : function(index){
11376 this.onUpdate(this.store, this.store.getAt(index));
11379 updateIndexes : function(startIndex, endIndex){
11380 var ns = this.nodes;
11381 startIndex = startIndex || 0;
11382 endIndex = endIndex || ns.length - 1;
11383 for(var i = startIndex; i <= endIndex; i++){
11384 ns[i].nodeIndex = i;
11389 * Changes the data store this view uses and refresh the view.
11390 * @param {Store} store
11392 setStore : function(store, initial){
11393 if(!initial && this.store){
11394 this.store.un("datachanged", this.refresh);
11395 this.store.un("add", this.onAdd);
11396 this.store.un("remove", this.onRemove);
11397 this.store.un("update", this.onUpdate);
11398 this.store.un("clear", this.refresh);
11399 this.store.un("beforeload", this.onBeforeLoad);
11400 this.store.un("load", this.onLoad);
11401 this.store.un("loadexception", this.onLoad);
11405 store.on("datachanged", this.refresh, this);
11406 store.on("add", this.onAdd, this);
11407 store.on("remove", this.onRemove, this);
11408 store.on("update", this.onUpdate, this);
11409 store.on("clear", this.refresh, this);
11410 store.on("beforeload", this.onBeforeLoad, this);
11411 store.on("load", this.onLoad, this);
11412 store.on("loadexception", this.onLoad, this);
11420 * onbeforeLoad - masks the loading area.
11423 onBeforeLoad : function(store,opts)
11425 Roo.log('onBeforeLoad');
11427 this.el.update("");
11429 this.el.mask(this.mask ? this.mask : "Loading" );
11431 onLoad : function ()
11438 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11439 * @param {HTMLElement} node
11440 * @return {HTMLElement} The template node
11442 findItemFromChild : function(node){
11443 var el = this.dataName ?
11444 this.el.child('.roo-tpl-' + this.dataName,true) :
11447 if(!node || node.parentNode == el){
11450 var p = node.parentNode;
11451 while(p && p != el){
11452 if(p.parentNode == el){
11461 onClick : function(e){
11462 var item = this.findItemFromChild(e.getTarget());
11464 var index = this.indexOf(item);
11465 if(this.onItemClick(item, index, e) !== false){
11466 this.fireEvent("click", this, index, item, e);
11469 this.clearSelections();
11474 onContextMenu : function(e){
11475 var item = this.findItemFromChild(e.getTarget());
11477 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
11482 onDblClick : function(e){
11483 var item = this.findItemFromChild(e.getTarget());
11485 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
11489 onItemClick : function(item, index, e)
11491 if(this.fireEvent("beforeclick", this, index, item, e) === false){
11494 if (this.toggleSelect) {
11495 var m = this.isSelected(item) ? 'unselect' : 'select';
11498 _t[m](item, true, false);
11501 if(this.multiSelect || this.singleSelect){
11502 if(this.multiSelect && e.shiftKey && this.lastSelection){
11503 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
11505 this.select(item, this.multiSelect && e.ctrlKey);
11506 this.lastSelection = item;
11508 e.preventDefault();
11514 * Get the number of selected nodes.
11517 getSelectionCount : function(){
11518 return this.selections.length;
11522 * Get the currently selected nodes.
11523 * @return {Array} An array of HTMLElements
11525 getSelectedNodes : function(){
11526 return this.selections;
11530 * Get the indexes of the selected nodes.
11533 getSelectedIndexes : function(){
11534 var indexes = [], s = this.selections;
11535 for(var i = 0, len = s.length; i < len; i++){
11536 indexes.push(s[i].nodeIndex);
11542 * Clear all selections
11543 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
11545 clearSelections : function(suppressEvent){
11546 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
11547 this.cmp.elements = this.selections;
11548 this.cmp.removeClass(this.selectedClass);
11549 this.selections = [];
11550 if(!suppressEvent){
11551 this.fireEvent("selectionchange", this, this.selections);
11557 * Returns true if the passed node is selected
11558 * @param {HTMLElement/Number} node The node or node index
11559 * @return {Boolean}
11561 isSelected : function(node){
11562 var s = this.selections;
11566 node = this.getNode(node);
11567 return s.indexOf(node) !== -1;
11572 * @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
11573 * @param {Boolean} keepExisting (optional) true to keep existing selections
11574 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11576 select : function(nodeInfo, keepExisting, suppressEvent){
11577 if(nodeInfo instanceof Array){
11579 this.clearSelections(true);
11581 for(var i = 0, len = nodeInfo.length; i < len; i++){
11582 this.select(nodeInfo[i], true, true);
11586 var node = this.getNode(nodeInfo);
11587 if(!node || this.isSelected(node)){
11588 return; // already selected.
11591 this.clearSelections(true);
11593 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
11594 Roo.fly(node).addClass(this.selectedClass);
11595 this.selections.push(node);
11596 if(!suppressEvent){
11597 this.fireEvent("selectionchange", this, this.selections);
11605 * @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
11606 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
11607 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11609 unselect : function(nodeInfo, keepExisting, suppressEvent)
11611 if(nodeInfo instanceof Array){
11612 Roo.each(this.selections, function(s) {
11613 this.unselect(s, nodeInfo);
11617 var node = this.getNode(nodeInfo);
11618 if(!node || !this.isSelected(node)){
11619 Roo.log("not selected");
11620 return; // not selected.
11624 Roo.each(this.selections, function(s) {
11626 Roo.fly(node).removeClass(this.selectedClass);
11633 this.selections= ns;
11634 this.fireEvent("selectionchange", this, this.selections);
11638 * Gets a template node.
11639 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11640 * @return {HTMLElement} The node or null if it wasn't found
11642 getNode : function(nodeInfo){
11643 if(typeof nodeInfo == "string"){
11644 return document.getElementById(nodeInfo);
11645 }else if(typeof nodeInfo == "number"){
11646 return this.nodes[nodeInfo];
11652 * Gets a range template nodes.
11653 * @param {Number} startIndex
11654 * @param {Number} endIndex
11655 * @return {Array} An array of nodes
11657 getNodes : function(start, end){
11658 var ns = this.nodes;
11659 start = start || 0;
11660 end = typeof end == "undefined" ? ns.length - 1 : end;
11663 for(var i = start; i <= end; i++){
11667 for(var i = start; i >= end; i--){
11675 * Finds the index of the passed node
11676 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11677 * @return {Number} The index of the node or -1
11679 indexOf : function(node){
11680 node = this.getNode(node);
11681 if(typeof node.nodeIndex == "number"){
11682 return node.nodeIndex;
11684 var ns = this.nodes;
11685 for(var i = 0, len = ns.length; i < len; i++){
11696 * based on jquery fullcalendar
11700 Roo.bootstrap = Roo.bootstrap || {};
11702 * @class Roo.bootstrap.Calendar
11703 * @extends Roo.bootstrap.Component
11704 * Bootstrap Calendar class
11705 * @cfg {Boolean} loadMask (true|false) default false
11706 * @cfg {Object} header generate the user specific header of the calendar, default false
11709 * Create a new Container
11710 * @param {Object} config The config object
11715 Roo.bootstrap.Calendar = function(config){
11716 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11720 * Fires when a date is selected
11721 * @param {DatePicker} this
11722 * @param {Date} date The selected date
11726 * @event monthchange
11727 * Fires when the displayed month changes
11728 * @param {DatePicker} this
11729 * @param {Date} date The selected month
11731 'monthchange': true,
11733 * @event evententer
11734 * Fires when mouse over an event
11735 * @param {Calendar} this
11736 * @param {event} Event
11738 'evententer': true,
11740 * @event eventleave
11741 * Fires when the mouse leaves an
11742 * @param {Calendar} this
11745 'eventleave': true,
11747 * @event eventclick
11748 * Fires when the mouse click an
11749 * @param {Calendar} this
11758 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11761 * @cfg {Number} startDay
11762 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11770 getAutoCreate : function(){
11773 var fc_button = function(name, corner, style, content ) {
11774 return Roo.apply({},{
11776 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11778 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11781 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11792 style : 'width:100%',
11799 cls : 'fc-header-left',
11801 fc_button('prev', 'left', 'arrow', '‹' ),
11802 fc_button('next', 'right', 'arrow', '›' ),
11803 { tag: 'span', cls: 'fc-header-space' },
11804 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11812 cls : 'fc-header-center',
11816 cls: 'fc-header-title',
11819 html : 'month / year'
11827 cls : 'fc-header-right',
11829 /* fc_button('month', 'left', '', 'month' ),
11830 fc_button('week', '', '', 'week' ),
11831 fc_button('day', 'right', '', 'day' )
11843 header = this.header;
11846 var cal_heads = function() {
11848 // fixme - handle this.
11850 for (var i =0; i < Date.dayNames.length; i++) {
11851 var d = Date.dayNames[i];
11854 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11855 html : d.substring(0,3)
11859 ret[0].cls += ' fc-first';
11860 ret[6].cls += ' fc-last';
11863 var cal_cell = function(n) {
11866 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11871 cls: 'fc-day-number',
11875 cls: 'fc-day-content',
11879 style: 'position: relative;' // height: 17px;
11891 var cal_rows = function() {
11894 for (var r = 0; r < 6; r++) {
11901 for (var i =0; i < Date.dayNames.length; i++) {
11902 var d = Date.dayNames[i];
11903 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11906 row.cn[0].cls+=' fc-first';
11907 row.cn[0].cn[0].style = 'min-height:90px';
11908 row.cn[6].cls+=' fc-last';
11912 ret[0].cls += ' fc-first';
11913 ret[4].cls += ' fc-prev-last';
11914 ret[5].cls += ' fc-last';
11921 cls: 'fc-border-separate',
11922 style : 'width:100%',
11930 cls : 'fc-first fc-last',
11948 cls : 'fc-content',
11949 style : "position: relative;",
11952 cls : 'fc-view fc-view-month fc-grid',
11953 style : 'position: relative',
11954 unselectable : 'on',
11957 cls : 'fc-event-container',
11958 style : 'position:absolute;z-index:8;top:0;left:0;'
11976 initEvents : function()
11979 throw "can not find store for calendar";
11985 style: "text-align:center",
11989 style: "background-color:white;width:50%;margin:250 auto",
11993 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12004 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12006 var size = this.el.select('.fc-content', true).first().getSize();
12007 this.maskEl.setSize(size.width, size.height);
12008 this.maskEl.enableDisplayMode("block");
12009 if(!this.loadMask){
12010 this.maskEl.hide();
12013 this.store = Roo.factory(this.store, Roo.data);
12014 this.store.on('load', this.onLoad, this);
12015 this.store.on('beforeload', this.onBeforeLoad, this);
12019 this.cells = this.el.select('.fc-day',true);
12020 //Roo.log(this.cells);
12021 this.textNodes = this.el.query('.fc-day-number');
12022 this.cells.addClassOnOver('fc-state-hover');
12024 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12025 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12026 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12027 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12029 this.on('monthchange', this.onMonthChange, this);
12031 this.update(new Date().clearTime());
12034 resize : function() {
12035 var sz = this.el.getSize();
12037 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12038 this.el.select('.fc-day-content div',true).setHeight(34);
12043 showPrevMonth : function(e){
12044 this.update(this.activeDate.add("mo", -1));
12046 showToday : function(e){
12047 this.update(new Date().clearTime());
12050 showNextMonth : function(e){
12051 this.update(this.activeDate.add("mo", 1));
12055 showPrevYear : function(){
12056 this.update(this.activeDate.add("y", -1));
12060 showNextYear : function(){
12061 this.update(this.activeDate.add("y", 1));
12066 update : function(date)
12068 var vd = this.activeDate;
12069 this.activeDate = date;
12070 // if(vd && this.el){
12071 // var t = date.getTime();
12072 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12073 // Roo.log('using add remove');
12075 // this.fireEvent('monthchange', this, date);
12077 // this.cells.removeClass("fc-state-highlight");
12078 // this.cells.each(function(c){
12079 // if(c.dateValue == t){
12080 // c.addClass("fc-state-highlight");
12081 // setTimeout(function(){
12082 // try{c.dom.firstChild.focus();}catch(e){}
12092 var days = date.getDaysInMonth();
12094 var firstOfMonth = date.getFirstDateOfMonth();
12095 var startingPos = firstOfMonth.getDay()-this.startDay;
12097 if(startingPos < this.startDay){
12101 var pm = date.add(Date.MONTH, -1);
12102 var prevStart = pm.getDaysInMonth()-startingPos;
12104 this.cells = this.el.select('.fc-day',true);
12105 this.textNodes = this.el.query('.fc-day-number');
12106 this.cells.addClassOnOver('fc-state-hover');
12108 var cells = this.cells.elements;
12109 var textEls = this.textNodes;
12111 Roo.each(cells, function(cell){
12112 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12115 days += startingPos;
12117 // convert everything to numbers so it's fast
12118 var day = 86400000;
12119 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12122 //Roo.log(prevStart);
12124 var today = new Date().clearTime().getTime();
12125 var sel = date.clearTime().getTime();
12126 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12127 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12128 var ddMatch = this.disabledDatesRE;
12129 var ddText = this.disabledDatesText;
12130 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12131 var ddaysText = this.disabledDaysText;
12132 var format = this.format;
12134 var setCellClass = function(cal, cell){
12138 //Roo.log('set Cell Class');
12140 var t = d.getTime();
12144 cell.dateValue = t;
12146 cell.className += " fc-today";
12147 cell.className += " fc-state-highlight";
12148 cell.title = cal.todayText;
12151 // disable highlight in other month..
12152 //cell.className += " fc-state-highlight";
12157 cell.className = " fc-state-disabled";
12158 cell.title = cal.minText;
12162 cell.className = " fc-state-disabled";
12163 cell.title = cal.maxText;
12167 if(ddays.indexOf(d.getDay()) != -1){
12168 cell.title = ddaysText;
12169 cell.className = " fc-state-disabled";
12172 if(ddMatch && format){
12173 var fvalue = d.dateFormat(format);
12174 if(ddMatch.test(fvalue)){
12175 cell.title = ddText.replace("%0", fvalue);
12176 cell.className = " fc-state-disabled";
12180 if (!cell.initialClassName) {
12181 cell.initialClassName = cell.dom.className;
12184 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12189 for(; i < startingPos; i++) {
12190 textEls[i].innerHTML = (++prevStart);
12191 d.setDate(d.getDate()+1);
12193 cells[i].className = "fc-past fc-other-month";
12194 setCellClass(this, cells[i]);
12199 for(; i < days; i++){
12200 intDay = i - startingPos + 1;
12201 textEls[i].innerHTML = (intDay);
12202 d.setDate(d.getDate()+1);
12204 cells[i].className = ''; // "x-date-active";
12205 setCellClass(this, cells[i]);
12209 for(; i < 42; i++) {
12210 textEls[i].innerHTML = (++extraDays);
12211 d.setDate(d.getDate()+1);
12213 cells[i].className = "fc-future fc-other-month";
12214 setCellClass(this, cells[i]);
12217 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12219 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12221 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12222 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12224 if(totalRows != 6){
12225 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12226 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12229 this.fireEvent('monthchange', this, date);
12233 if(!this.internalRender){
12234 var main = this.el.dom.firstChild;
12235 var w = main.offsetWidth;
12236 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12237 Roo.fly(main).setWidth(w);
12238 this.internalRender = true;
12239 // opera does not respect the auto grow header center column
12240 // then, after it gets a width opera refuses to recalculate
12241 // without a second pass
12242 if(Roo.isOpera && !this.secondPass){
12243 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12244 this.secondPass = true;
12245 this.update.defer(10, this, [date]);
12252 findCell : function(dt) {
12253 dt = dt.clearTime().getTime();
12255 this.cells.each(function(c){
12256 //Roo.log("check " +c.dateValue + '?=' + dt);
12257 if(c.dateValue == dt){
12267 findCells : function(ev) {
12268 var s = ev.start.clone().clearTime().getTime();
12270 var e= ev.end.clone().clearTime().getTime();
12273 this.cells.each(function(c){
12274 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12276 if(c.dateValue > e){
12279 if(c.dateValue < s){
12288 // findBestRow: function(cells)
12292 // for (var i =0 ; i < cells.length;i++) {
12293 // ret = Math.max(cells[i].rows || 0,ret);
12300 addItem : function(ev)
12302 // look for vertical location slot in
12303 var cells = this.findCells(ev);
12305 // ev.row = this.findBestRow(cells);
12307 // work out the location.
12311 for(var i =0; i < cells.length; i++) {
12313 cells[i].row = cells[0].row;
12316 cells[i].row = cells[i].row + 1;
12326 if (crow.start.getY() == cells[i].getY()) {
12328 crow.end = cells[i];
12345 cells[0].events.push(ev);
12347 this.calevents.push(ev);
12350 clearEvents: function() {
12352 if(!this.calevents){
12356 Roo.each(this.cells.elements, function(c){
12362 Roo.each(this.calevents, function(e) {
12363 Roo.each(e.els, function(el) {
12364 el.un('mouseenter' ,this.onEventEnter, this);
12365 el.un('mouseleave' ,this.onEventLeave, this);
12370 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12376 renderEvents: function()
12380 this.cells.each(function(c) {
12389 if(c.row != c.events.length){
12390 r = 4 - (4 - (c.row - c.events.length));
12393 c.events = ev.slice(0, r);
12394 c.more = ev.slice(r);
12396 if(c.more.length && c.more.length == 1){
12397 c.events.push(c.more.pop());
12400 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12404 this.cells.each(function(c) {
12406 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12409 for (var e = 0; e < c.events.length; e++){
12410 var ev = c.events[e];
12411 var rows = ev.rows;
12413 for(var i = 0; i < rows.length; i++) {
12415 // how many rows should it span..
12418 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12419 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12421 unselectable : "on",
12424 cls: 'fc-event-inner',
12428 // cls: 'fc-event-time',
12429 // html : cells.length > 1 ? '' : ev.time
12433 cls: 'fc-event-title',
12434 html : String.format('{0}', ev.title)
12441 cls: 'ui-resizable-handle ui-resizable-e',
12442 html : '  '
12449 cfg.cls += ' fc-event-start';
12451 if ((i+1) == rows.length) {
12452 cfg.cls += ' fc-event-end';
12455 var ctr = _this.el.select('.fc-event-container',true).first();
12456 var cg = ctr.createChild(cfg);
12458 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
12459 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
12461 var r = (c.more.length) ? 1 : 0;
12462 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
12463 cg.setWidth(ebox.right - sbox.x -2);
12465 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
12466 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
12467 cg.on('click', _this.onEventClick, _this, ev);
12478 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
12479 style : 'position: absolute',
12480 unselectable : "on",
12483 cls: 'fc-event-inner',
12487 cls: 'fc-event-title',
12495 cls: 'ui-resizable-handle ui-resizable-e',
12496 html : '  '
12502 var ctr = _this.el.select('.fc-event-container',true).first();
12503 var cg = ctr.createChild(cfg);
12505 var sbox = c.select('.fc-day-content',true).first().getBox();
12506 var ebox = c.select('.fc-day-content',true).first().getBox();
12508 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
12509 cg.setWidth(ebox.right - sbox.x -2);
12511 cg.on('click', _this.onMoreEventClick, _this, c.more);
12521 onEventEnter: function (e, el,event,d) {
12522 this.fireEvent('evententer', this, el, event);
12525 onEventLeave: function (e, el,event,d) {
12526 this.fireEvent('eventleave', this, el, event);
12529 onEventClick: function (e, el,event,d) {
12530 this.fireEvent('eventclick', this, el, event);
12533 onMonthChange: function () {
12537 onMoreEventClick: function(e, el, more)
12541 this.calpopover.placement = 'right';
12542 this.calpopover.setTitle('More');
12544 this.calpopover.setContent('');
12546 var ctr = this.calpopover.el.select('.popover-content', true).first();
12548 Roo.each(more, function(m){
12550 cls : 'fc-event-hori fc-event-draggable',
12553 var cg = ctr.createChild(cfg);
12555 cg.on('click', _this.onEventClick, _this, m);
12558 this.calpopover.show(el);
12563 onLoad: function ()
12565 this.calevents = [];
12568 if(this.store.getCount() > 0){
12569 this.store.data.each(function(d){
12572 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
12573 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
12574 time : d.data.start_time,
12575 title : d.data.title,
12576 description : d.data.description,
12577 venue : d.data.venue
12582 this.renderEvents();
12584 if(this.calevents.length && this.loadMask){
12585 this.maskEl.hide();
12589 onBeforeLoad: function()
12591 this.clearEvents();
12593 this.maskEl.show();
12607 * @class Roo.bootstrap.Popover
12608 * @extends Roo.bootstrap.Component
12609 * Bootstrap Popover class
12610 * @cfg {String} html contents of the popover (or false to use children..)
12611 * @cfg {String} title of popover (or false to hide)
12612 * @cfg {String} placement how it is placed
12613 * @cfg {String} trigger click || hover (or false to trigger manually)
12614 * @cfg {String} over what (parent or false to trigger manually.)
12617 * Create a new Popover
12618 * @param {Object} config The config object
12621 Roo.bootstrap.Popover = function(config){
12622 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
12625 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
12627 title: 'Fill in a title',
12630 placement : 'right',
12631 trigger : 'hover', // hover
12635 can_build_overlaid : false,
12637 getChildContainer : function()
12639 return this.el.select('.popover-content',true).first();
12642 getAutoCreate : function(){
12643 Roo.log('make popover?');
12645 cls : 'popover roo-dynamic',
12646 style: 'display:block',
12652 cls : 'popover-inner',
12656 cls: 'popover-title',
12660 cls : 'popover-content',
12671 setTitle: function(str)
12673 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12675 setContent: function(str)
12677 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12679 // as it get's added to the bottom of the page.
12680 onRender : function(ct, position)
12682 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12684 var cfg = Roo.apply({}, this.getAutoCreate());
12688 cfg.cls += ' ' + this.cls;
12691 cfg.style = this.style;
12693 Roo.log("adding to ")
12694 this.el = Roo.get(document.body).createChild(cfg, position);
12700 initEvents : function()
12702 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12703 this.el.enableDisplayMode('block');
12705 if (this.over === false) {
12708 if (this.triggers === false) {
12711 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12712 var triggers = this.trigger ? this.trigger.split(' ') : [];
12713 Roo.each(triggers, function(trigger) {
12715 if (trigger == 'click') {
12716 on_el.on('click', this.toggle, this);
12717 } else if (trigger != 'manual') {
12718 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12719 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12721 on_el.on(eventIn ,this.enter, this);
12722 on_el.on(eventOut, this.leave, this);
12733 toggle : function () {
12734 this.hoverState == 'in' ? this.leave() : this.enter();
12737 enter : function () {
12740 clearTimeout(this.timeout);
12742 this.hoverState = 'in'
12744 if (!this.delay || !this.delay.show) {
12749 this.timeout = setTimeout(function () {
12750 if (_t.hoverState == 'in') {
12753 }, this.delay.show)
12755 leave : function() {
12756 clearTimeout(this.timeout);
12758 this.hoverState = 'out'
12760 if (!this.delay || !this.delay.hide) {
12765 this.timeout = setTimeout(function () {
12766 if (_t.hoverState == 'out') {
12769 }, this.delay.hide)
12772 show : function (on_el)
12775 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12778 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12779 if (this.html !== false) {
12780 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12782 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12783 if (!this.title.length) {
12784 this.el.select('.popover-title',true).hide();
12787 var placement = typeof this.placement == 'function' ?
12788 this.placement.call(this, this.el, on_el) :
12791 var autoToken = /\s?auto?\s?/i;
12792 var autoPlace = autoToken.test(placement);
12794 placement = placement.replace(autoToken, '') || 'top';
12798 //this.el.setXY([0,0]);
12800 this.el.dom.style.display='block';
12801 this.el.addClass(placement);
12803 //this.el.appendTo(on_el);
12805 var p = this.getPosition();
12806 var box = this.el.getBox();
12811 var align = Roo.bootstrap.Popover.alignment[placement]
12812 this.el.alignTo(on_el, align[0],align[1]);
12813 //var arrow = this.el.select('.arrow',true).first();
12814 //arrow.set(align[2],
12816 this.el.addClass('in');
12817 this.hoverState = null;
12819 if (this.el.hasClass('fade')) {
12826 this.el.setXY([0,0]);
12827 this.el.removeClass('in');
12834 Roo.bootstrap.Popover.alignment = {
12835 'left' : ['r-l', [-10,0], 'right'],
12836 'right' : ['l-r', [10,0], 'left'],
12837 'bottom' : ['t-b', [0,10], 'top'],
12838 'top' : [ 'b-t', [0,-10], 'bottom']
12849 * @class Roo.bootstrap.Progress
12850 * @extends Roo.bootstrap.Component
12851 * Bootstrap Progress class
12852 * @cfg {Boolean} striped striped of the progress bar
12853 * @cfg {Boolean} active animated of the progress bar
12857 * Create a new Progress
12858 * @param {Object} config The config object
12861 Roo.bootstrap.Progress = function(config){
12862 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12865 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12870 getAutoCreate : function(){
12878 cfg.cls += ' progress-striped';
12882 cfg.cls += ' active';
12901 * @class Roo.bootstrap.ProgressBar
12902 * @extends Roo.bootstrap.Component
12903 * Bootstrap ProgressBar class
12904 * @cfg {Number} aria_valuenow aria-value now
12905 * @cfg {Number} aria_valuemin aria-value min
12906 * @cfg {Number} aria_valuemax aria-value max
12907 * @cfg {String} label label for the progress bar
12908 * @cfg {String} panel (success | info | warning | danger )
12909 * @cfg {String} role role of the progress bar
12910 * @cfg {String} sr_only text
12914 * Create a new ProgressBar
12915 * @param {Object} config The config object
12918 Roo.bootstrap.ProgressBar = function(config){
12919 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12922 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12926 aria_valuemax : 100,
12932 getAutoCreate : function()
12937 cls: 'progress-bar',
12938 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12950 cfg.role = this.role;
12953 if(this.aria_valuenow){
12954 cfg['aria-valuenow'] = this.aria_valuenow;
12957 if(this.aria_valuemin){
12958 cfg['aria-valuemin'] = this.aria_valuemin;
12961 if(this.aria_valuemax){
12962 cfg['aria-valuemax'] = this.aria_valuemax;
12965 if(this.label && !this.sr_only){
12966 cfg.html = this.label;
12970 cfg.cls += ' progress-bar-' + this.panel;
12976 update : function(aria_valuenow)
12978 this.aria_valuenow = aria_valuenow;
12980 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12995 * @class Roo.bootstrap.TabPanel
12996 * @extends Roo.bootstrap.Component
12997 * Bootstrap TabPanel class
12998 * @cfg {Boolean} active panel active
12999 * @cfg {String} html panel content
13000 * @cfg {String} tabId tab relate id
13001 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13005 * Create a new TabPanel
13006 * @param {Object} config The config object
13009 Roo.bootstrap.TabPanel = function(config){
13010 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13014 * Fires when the active status changes
13015 * @param {Roo.bootstrap.TabPanel} this
13016 * @param {Boolean} state the new state
13023 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13030 getAutoCreate : function(){
13034 html: this.html || ''
13038 cfg.cls += ' active';
13042 cfg.tabId = this.tabId;
13047 onRender : function(ct, position)
13049 // Roo.log("Call onRender: " + this.xtype);
13051 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13053 if (this.navId && this.tabId) {
13054 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13056 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13058 item.on('changed', function(item, state) {
13059 this.setActive(state);
13065 setActive: function(state)
13067 Roo.log("panel - set active " + this.tabId + "=" + state);
13069 this.active = state;
13071 this.el.removeClass('active');
13073 } else if (!this.el.hasClass('active')) {
13074 this.el.addClass('active');
13076 this.fireEvent('changed', this, state);
13093 * @class Roo.bootstrap.DateField
13094 * @extends Roo.bootstrap.Input
13095 * Bootstrap DateField class
13096 * @cfg {Number} weekStart default 0
13097 * @cfg {Number} weekStart default 0
13098 * @cfg {Number} viewMode default empty, (months|years)
13099 * @cfg {Number} minViewMode default empty, (months|years)
13100 * @cfg {Number} startDate default -Infinity
13101 * @cfg {Number} endDate default Infinity
13102 * @cfg {Boolean} todayHighlight default false
13103 * @cfg {Boolean} todayBtn default false
13104 * @cfg {Boolean} calendarWeeks default false
13105 * @cfg {Object} daysOfWeekDisabled default empty
13107 * @cfg {Boolean} keyboardNavigation default true
13108 * @cfg {String} language default en
13111 * Create a new DateField
13112 * @param {Object} config The config object
13115 Roo.bootstrap.DateField = function(config){
13116 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13120 * Fires when this field show.
13121 * @param {Roo.bootstrap.DateField} this
13122 * @param {Mixed} date The date value
13127 * Fires when this field hide.
13128 * @param {Roo.bootstrap.DateField} this
13129 * @param {Mixed} date The date value
13134 * Fires when select a date.
13135 * @param {Roo.bootstrap.DateField} this
13136 * @param {Mixed} date The date value
13142 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13145 * @cfg {String} format
13146 * The default date format string which can be overriden for localization support. The format must be
13147 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13151 * @cfg {String} altFormats
13152 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13153 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13155 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13163 todayHighlight : false,
13169 keyboardNavigation: true,
13171 calendarWeeks: false,
13173 startDate: -Infinity,
13177 daysOfWeekDisabled: [],
13181 UTCDate: function()
13183 return new Date(Date.UTC.apply(Date, arguments));
13186 UTCToday: function()
13188 var today = new Date();
13189 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13192 getDate: function() {
13193 var d = this.getUTCDate();
13194 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13197 getUTCDate: function() {
13201 setDate: function(d) {
13202 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13205 setUTCDate: function(d) {
13207 this.setValue(this.formatDate(this.date));
13210 onRender: function(ct, position)
13213 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13215 this.language = this.language || 'en';
13216 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13217 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13219 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13220 this.format = this.format || 'm/d/y';
13221 this.isInline = false;
13222 this.isInput = true;
13223 this.component = this.el.select('.add-on', true).first() || false;
13224 this.component = (this.component && this.component.length === 0) ? false : this.component;
13225 this.hasInput = this.component && this.inputEL().length;
13227 if (typeof(this.minViewMode === 'string')) {
13228 switch (this.minViewMode) {
13230 this.minViewMode = 1;
13233 this.minViewMode = 2;
13236 this.minViewMode = 0;
13241 if (typeof(this.viewMode === 'string')) {
13242 switch (this.viewMode) {
13255 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13257 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13259 this.picker().on('mousedown', this.onMousedown, this);
13260 this.picker().on('click', this.onClick, this);
13262 this.picker().addClass('datepicker-dropdown');
13264 this.startViewMode = this.viewMode;
13267 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13268 if(!this.calendarWeeks){
13273 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13274 v.attr('colspan', function(i, val){
13275 return parseInt(val) + 1;
13280 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13282 this.setStartDate(this.startDate);
13283 this.setEndDate(this.endDate);
13285 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13292 if(this.isInline) {
13297 picker : function()
13299 return this.el.select('.datepicker', true).first();
13302 fillDow: function()
13304 var dowCnt = this.weekStart;
13313 if(this.calendarWeeks){
13321 while (dowCnt < this.weekStart + 7) {
13325 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13329 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13332 fillMonths: function()
13335 var months = this.picker().select('>.datepicker-months td', true).first();
13337 months.dom.innerHTML = '';
13343 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13346 months.createChild(month);
13351 update: function(){
13353 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13355 if (this.date < this.startDate) {
13356 this.viewDate = new Date(this.startDate);
13357 } else if (this.date > this.endDate) {
13358 this.viewDate = new Date(this.endDate);
13360 this.viewDate = new Date(this.date);
13367 var d = new Date(this.viewDate),
13368 year = d.getUTCFullYear(),
13369 month = d.getUTCMonth(),
13370 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13371 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13372 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13373 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13374 currentDate = this.date && this.date.valueOf(),
13375 today = this.UTCToday();
13377 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13379 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13381 // this.picker.select('>tfoot th.today').
13382 // .text(dates[this.language].today)
13383 // .toggle(this.todayBtn !== false);
13385 this.updateNavArrows();
13388 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13390 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13392 prevMonth.setUTCDate(day);
13394 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13396 var nextMonth = new Date(prevMonth);
13398 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13400 nextMonth = nextMonth.valueOf();
13402 var fillMonths = false;
13404 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13406 while(prevMonth.valueOf() < nextMonth) {
13409 if (prevMonth.getUTCDay() === this.weekStart) {
13411 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13419 if(this.calendarWeeks){
13420 // ISO 8601: First week contains first thursday.
13421 // ISO also states week starts on Monday, but we can be more abstract here.
13423 // Start of current week: based on weekstart/current date
13424 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13425 // Thursday of this week
13426 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13427 // First Thursday of year, year from thursday
13428 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13429 // Calendar week: ms between thursdays, div ms per day, div 7 days
13430 calWeek = (th - yth) / 864e5 / 7 + 1;
13432 fillMonths.cn.push({
13440 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13442 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13445 if (this.todayHighlight &&
13446 prevMonth.getUTCFullYear() == today.getFullYear() &&
13447 prevMonth.getUTCMonth() == today.getMonth() &&
13448 prevMonth.getUTCDate() == today.getDate()) {
13449 clsName += ' today';
13452 if (currentDate && prevMonth.valueOf() === currentDate) {
13453 clsName += ' active';
13456 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
13457 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
13458 clsName += ' disabled';
13461 fillMonths.cn.push({
13463 cls: 'day ' + clsName,
13464 html: prevMonth.getDate()
13467 prevMonth.setDate(prevMonth.getDate()+1);
13470 var currentYear = this.date && this.date.getUTCFullYear();
13471 var currentMonth = this.date && this.date.getUTCMonth();
13473 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
13475 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
13476 v.removeClass('active');
13478 if(currentYear === year && k === currentMonth){
13479 v.addClass('active');
13482 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
13483 v.addClass('disabled');
13489 year = parseInt(year/10, 10) * 10;
13491 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
13493 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
13496 for (var i = -1; i < 11; i++) {
13497 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
13499 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
13507 showMode: function(dir) {
13509 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
13511 Roo.each(this.picker().select('>div',true).elements, function(v){
13512 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13515 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
13520 if(this.isInline) return;
13522 this.picker().removeClass(['bottom', 'top']);
13524 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13526 * place to the top of element!
13530 this.picker().addClass('top');
13531 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13536 this.picker().addClass('bottom');
13538 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13541 parseDate : function(value){
13542 if(!value || value instanceof Date){
13545 var v = Date.parseDate(value, this.format);
13546 if (!v && this.useIso) {
13547 v = Date.parseDate(value, 'Y-m-d');
13549 if(!v && this.altFormats){
13550 if(!this.altFormatsArray){
13551 this.altFormatsArray = this.altFormats.split("|");
13553 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
13554 v = Date.parseDate(value, this.altFormatsArray[i]);
13560 formatDate : function(date, fmt){
13561 return (!date || !(date instanceof Date)) ?
13562 date : date.dateFormat(fmt || this.format);
13565 onFocus : function()
13567 Roo.bootstrap.DateField.superclass.onFocus.call(this);
13571 onBlur : function()
13573 Roo.bootstrap.DateField.superclass.onBlur.call(this);
13579 this.picker().show();
13583 this.fireEvent('show', this, this.date);
13588 if(this.isInline) return;
13589 this.picker().hide();
13590 this.viewMode = this.startViewMode;
13593 this.fireEvent('hide', this, this.date);
13597 onMousedown: function(e){
13598 e.stopPropagation();
13599 e.preventDefault();
13602 keyup: function(e){
13603 Roo.bootstrap.DateField.superclass.keyup.call(this);
13608 setValue: function(v){
13609 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
13611 this.fireEvent('select', this, this.date);
13615 fireKey: function(e){
13616 if (!this.picker().isVisible()){
13617 if (e.keyCode == 27) // allow escape to hide and re-show picker
13621 var dateChanged = false,
13623 newDate, newViewDate;
13627 e.preventDefault();
13631 if (!this.keyboardNavigation) break;
13632 dir = e.keyCode == 37 ? -1 : 1;
13635 newDate = this.moveYear(this.date, dir);
13636 newViewDate = this.moveYear(this.viewDate, dir);
13637 } else if (e.shiftKey){
13638 newDate = this.moveMonth(this.date, dir);
13639 newViewDate = this.moveMonth(this.viewDate, dir);
13641 newDate = new Date(this.date);
13642 newDate.setUTCDate(this.date.getUTCDate() + dir);
13643 newViewDate = new Date(this.viewDate);
13644 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13646 if (this.dateWithinRange(newDate)){
13647 this.date = newDate;
13648 this.viewDate = newViewDate;
13649 this.setValue(this.formatDate(this.date));
13651 e.preventDefault();
13652 dateChanged = true;
13657 if (!this.keyboardNavigation) break;
13658 dir = e.keyCode == 38 ? -1 : 1;
13660 newDate = this.moveYear(this.date, dir);
13661 newViewDate = this.moveYear(this.viewDate, dir);
13662 } else if (e.shiftKey){
13663 newDate = this.moveMonth(this.date, dir);
13664 newViewDate = this.moveMonth(this.viewDate, dir);
13666 newDate = new Date(this.date);
13667 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13668 newViewDate = new Date(this.viewDate);
13669 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13671 if (this.dateWithinRange(newDate)){
13672 this.date = newDate;
13673 this.viewDate = newViewDate;
13674 this.setValue(this.formatDate(this.date));
13676 e.preventDefault();
13677 dateChanged = true;
13681 this.setValue(this.formatDate(this.date));
13683 e.preventDefault();
13686 this.setValue(this.formatDate(this.date));
13693 onClick: function(e) {
13694 e.stopPropagation();
13695 e.preventDefault();
13697 var target = e.getTarget();
13699 if(target.nodeName.toLowerCase() === 'i'){
13700 target = Roo.get(target).dom.parentNode;
13703 var nodeName = target.nodeName;
13704 var className = target.className;
13705 var html = target.innerHTML;
13707 switch(nodeName.toLowerCase()) {
13709 switch(className) {
13715 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13716 switch(this.viewMode){
13718 this.viewDate = this.moveMonth(this.viewDate, dir);
13722 this.viewDate = this.moveYear(this.viewDate, dir);
13728 var date = new Date();
13729 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13731 this.setValue(this.formatDate(this.date));
13737 if (className.indexOf('disabled') === -1) {
13738 this.viewDate.setUTCDate(1);
13739 if (className.indexOf('month') !== -1) {
13740 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13742 var year = parseInt(html, 10) || 0;
13743 this.viewDate.setUTCFullYear(year);
13752 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13753 var day = parseInt(html, 10) || 1;
13754 var year = this.viewDate.getUTCFullYear(),
13755 month = this.viewDate.getUTCMonth();
13757 if (className.indexOf('old') !== -1) {
13764 } else if (className.indexOf('new') !== -1) {
13772 this.date = this.UTCDate(year, month, day,0,0,0,0);
13773 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13775 this.setValue(this.formatDate(this.date));
13782 setStartDate: function(startDate){
13783 this.startDate = startDate || -Infinity;
13784 if (this.startDate !== -Infinity) {
13785 this.startDate = this.parseDate(this.startDate);
13788 this.updateNavArrows();
13791 setEndDate: function(endDate){
13792 this.endDate = endDate || Infinity;
13793 if (this.endDate !== Infinity) {
13794 this.endDate = this.parseDate(this.endDate);
13797 this.updateNavArrows();
13800 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13801 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13802 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13803 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13805 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13806 return parseInt(d, 10);
13809 this.updateNavArrows();
13812 updateNavArrows: function() {
13813 var d = new Date(this.viewDate),
13814 year = d.getUTCFullYear(),
13815 month = d.getUTCMonth();
13817 Roo.each(this.picker().select('.prev', true).elements, function(v){
13819 switch (this.viewMode) {
13822 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13828 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13835 Roo.each(this.picker().select('.next', true).elements, function(v){
13837 switch (this.viewMode) {
13840 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13846 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13854 moveMonth: function(date, dir){
13855 if (!dir) return date;
13856 var new_date = new Date(date.valueOf()),
13857 day = new_date.getUTCDate(),
13858 month = new_date.getUTCMonth(),
13859 mag = Math.abs(dir),
13861 dir = dir > 0 ? 1 : -1;
13864 // If going back one month, make sure month is not current month
13865 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13867 return new_date.getUTCMonth() == month;
13869 // If going forward one month, make sure month is as expected
13870 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13872 return new_date.getUTCMonth() != new_month;
13874 new_month = month + dir;
13875 new_date.setUTCMonth(new_month);
13876 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13877 if (new_month < 0 || new_month > 11)
13878 new_month = (new_month + 12) % 12;
13880 // For magnitudes >1, move one month at a time...
13881 for (var i=0; i<mag; i++)
13882 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13883 new_date = this.moveMonth(new_date, dir);
13884 // ...then reset the day, keeping it in the new month
13885 new_month = new_date.getUTCMonth();
13886 new_date.setUTCDate(day);
13888 return new_month != new_date.getUTCMonth();
13891 // Common date-resetting loop -- if date is beyond end of month, make it
13894 new_date.setUTCDate(--day);
13895 new_date.setUTCMonth(new_month);
13900 moveYear: function(date, dir){
13901 return this.moveMonth(date, dir*12);
13904 dateWithinRange: function(date){
13905 return date >= this.startDate && date <= this.endDate;
13909 remove: function() {
13910 this.picker().remove();
13915 Roo.apply(Roo.bootstrap.DateField, {
13926 html: '<i class="fa fa-arrow-left"/>'
13936 html: '<i class="fa fa-arrow-right"/>'
13978 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13979 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13980 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13981 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13982 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13995 navFnc: 'FullYear',
14000 navFnc: 'FullYear',
14005 Roo.apply(Roo.bootstrap.DateField, {
14009 cls: 'datepicker dropdown-menu',
14013 cls: 'datepicker-days',
14017 cls: 'table-condensed',
14019 Roo.bootstrap.DateField.head,
14023 Roo.bootstrap.DateField.footer
14030 cls: 'datepicker-months',
14034 cls: 'table-condensed',
14036 Roo.bootstrap.DateField.head,
14037 Roo.bootstrap.DateField.content,
14038 Roo.bootstrap.DateField.footer
14045 cls: 'datepicker-years',
14049 cls: 'table-condensed',
14051 Roo.bootstrap.DateField.head,
14052 Roo.bootstrap.DateField.content,
14053 Roo.bootstrap.DateField.footer
14072 * @class Roo.bootstrap.TimeField
14073 * @extends Roo.bootstrap.Input
14074 * Bootstrap DateField class
14078 * Create a new TimeField
14079 * @param {Object} config The config object
14082 Roo.bootstrap.TimeField = function(config){
14083 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14087 * Fires when this field show.
14088 * @param {Roo.bootstrap.DateField} this
14089 * @param {Mixed} date The date value
14094 * Fires when this field hide.
14095 * @param {Roo.bootstrap.DateField} this
14096 * @param {Mixed} date The date value
14101 * Fires when select a date.
14102 * @param {Roo.bootstrap.DateField} this
14103 * @param {Mixed} date The date value
14109 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14112 * @cfg {String} format
14113 * The default time format string which can be overriden for localization support. The format must be
14114 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14118 onRender: function(ct, position)
14121 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14123 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14125 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14127 this.pop = this.picker().select('>.datepicker-time',true).first();
14128 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14130 this.picker().on('mousedown', this.onMousedown, this);
14131 this.picker().on('click', this.onClick, this);
14133 this.picker().addClass('datepicker-dropdown');
14138 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14139 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14140 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14141 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14142 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14143 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14147 fireKey: function(e){
14148 if (!this.picker().isVisible()){
14149 if (e.keyCode == 27) // allow escape to hide and re-show picker
14154 e.preventDefault();
14162 this.onTogglePeriod();
14165 this.onIncrementMinutes();
14168 this.onDecrementMinutes();
14177 onClick: function(e) {
14178 e.stopPropagation();
14179 e.preventDefault();
14182 picker : function()
14184 return this.el.select('.datepicker', true).first();
14187 fillTime: function()
14189 var time = this.pop.select('tbody', true).first();
14191 time.dom.innerHTML = '';
14206 cls: 'hours-up glyphicon glyphicon-chevron-up'
14226 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14247 cls: 'timepicker-hour',
14262 cls: 'timepicker-minute',
14277 cls: 'btn btn-primary period',
14299 cls: 'hours-down glyphicon glyphicon-chevron-down'
14319 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14337 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14344 var hours = this.time.getHours();
14345 var minutes = this.time.getMinutes();
14358 hours = hours - 12;
14362 hours = '0' + hours;
14366 minutes = '0' + minutes;
14369 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14370 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14371 this.pop.select('button', true).first().dom.innerHTML = period;
14377 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14379 var cls = ['bottom'];
14381 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14388 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14393 this.picker().addClass(cls.join('-'));
14397 Roo.each(cls, function(c){
14399 _this.picker().setTop(_this.inputEl().getHeight());
14403 _this.picker().setTop(0 - _this.picker().getHeight());
14408 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14412 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
14419 onFocus : function()
14421 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
14425 onBlur : function()
14427 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
14433 this.picker().show();
14438 this.fireEvent('show', this, this.date);
14443 this.picker().hide();
14446 this.fireEvent('hide', this, this.date);
14449 setTime : function()
14452 this.setValue(this.time.format(this.format));
14454 this.fireEvent('select', this, this.date);
14459 onMousedown: function(e){
14460 e.stopPropagation();
14461 e.preventDefault();
14464 onIncrementHours: function()
14466 Roo.log('onIncrementHours');
14467 this.time = this.time.add(Date.HOUR, 1);
14472 onDecrementHours: function()
14474 Roo.log('onDecrementHours');
14475 this.time = this.time.add(Date.HOUR, -1);
14479 onIncrementMinutes: function()
14481 Roo.log('onIncrementMinutes');
14482 this.time = this.time.add(Date.MINUTE, 1);
14486 onDecrementMinutes: function()
14488 Roo.log('onDecrementMinutes');
14489 this.time = this.time.add(Date.MINUTE, -1);
14493 onTogglePeriod: function()
14495 Roo.log('onTogglePeriod');
14496 this.time = this.time.add(Date.HOUR, 12);
14503 Roo.apply(Roo.bootstrap.TimeField, {
14533 cls: 'btn btn-info ok',
14545 Roo.apply(Roo.bootstrap.TimeField, {
14549 cls: 'datepicker dropdown-menu',
14553 cls: 'datepicker-time',
14557 cls: 'table-condensed',
14559 Roo.bootstrap.TimeField.content,
14560 Roo.bootstrap.TimeField.footer
14579 * @class Roo.bootstrap.CheckBox
14580 * @extends Roo.bootstrap.Input
14581 * Bootstrap CheckBox class
14583 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
14584 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
14585 * @cfg {String} boxLabel The text that appears beside the checkbox
14586 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
14587 * @cfg {Boolean} checked initnal the element
14591 * Create a new CheckBox
14592 * @param {Object} config The config object
14595 Roo.bootstrap.CheckBox = function(config){
14596 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
14601 * Fires when the element is checked or unchecked.
14602 * @param {Roo.bootstrap.CheckBox} this This input
14603 * @param {Boolean} checked The new checked value
14609 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
14611 inputType: 'checkbox',
14618 getAutoCreate : function()
14620 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14626 cfg.cls = 'form-group checkbox' //input-group
14634 type : this.inputType,
14635 value : (!this.checked) ? this.valueOff : this.inputValue,
14636 cls : 'roo-checkbox', //'form-box',
14637 placeholder : this.placeholder || ''
14641 if (this.weight) { // Validity check?
14642 cfg.cls += " checkbox-" + this.weight;
14645 if (this.disabled) {
14646 input.disabled=true;
14650 input.checked = this.checked;
14654 input.name = this.name;
14658 input.cls += ' input-' + this.size;
14662 ['xs','sm','md','lg'].map(function(size){
14663 if (settings[size]) {
14664 cfg.cls += ' col-' + size + '-' + settings[size];
14670 var inputblock = input;
14675 if (this.before || this.after) {
14678 cls : 'input-group',
14682 inputblock.cn.push({
14684 cls : 'input-group-addon',
14688 inputblock.cn.push(input);
14690 inputblock.cn.push({
14692 cls : 'input-group-addon',
14699 if (align ==='left' && this.fieldLabel.length) {
14700 Roo.log("left and has label");
14706 cls : 'control-label col-md-' + this.labelWidth,
14707 html : this.fieldLabel
14711 cls : "col-md-" + (12 - this.labelWidth),
14718 } else if ( this.fieldLabel.length) {
14723 tag: this.boxLabel ? 'span' : 'label',
14725 cls: 'control-label box-input-label',
14726 //cls : 'input-group-addon',
14727 html : this.fieldLabel
14737 Roo.log(" no label && no align");
14738 cfg.cn = [ inputblock ] ;
14747 html: this.boxLabel
14759 * return the real input element.
14761 inputEl: function ()
14763 return this.el.select('input.roo-checkbox',true).first();
14768 return this.el.select('label.control-label',true).first();
14771 initEvents : function()
14773 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14775 this.inputEl().on('click', this.onClick, this);
14779 onClick : function()
14781 this.setChecked(!this.checked);
14784 setChecked : function(state,suppressEvent)
14786 this.checked = state;
14788 this.inputEl().dom.checked = state;
14790 if(suppressEvent !== true){
14791 this.fireEvent('check', this, state);
14794 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14798 setValue : function(v,suppressEvent)
14800 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14814 * @class Roo.bootstrap.Radio
14815 * @extends Roo.bootstrap.CheckBox
14816 * Bootstrap Radio class
14819 * Create a new Radio
14820 * @param {Object} config The config object
14823 Roo.bootstrap.Radio = function(config){
14824 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14828 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14830 inputType: 'radio',
14834 getAutoCreate : function()
14836 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14842 cfg.cls = 'form-group radio' //input-group
14847 type : this.inputType,
14848 value : (!this.checked) ? this.valueOff : this.inputValue,
14850 placeholder : this.placeholder || ''
14853 if (this.weight) { // Validity check?
14854 cfg.cls += " radio-" + this.weight;
14856 if (this.disabled) {
14857 input.disabled=true;
14861 input.checked = this.checked;
14865 input.name = this.name;
14869 input.cls += ' input-' + this.size;
14873 ['xs','sm','md','lg'].map(function(size){
14874 if (settings[size]) {
14875 cfg.cls += ' col-' + size + '-' + settings[size];
14879 var inputblock = input;
14881 if (this.before || this.after) {
14884 cls : 'input-group',
14888 inputblock.cn.push({
14890 cls : 'input-group-addon',
14894 inputblock.cn.push(input);
14896 inputblock.cn.push({
14898 cls : 'input-group-addon',
14905 if (align ==='left' && this.fieldLabel.length) {
14906 Roo.log("left and has label");
14912 cls : 'control-label col-md-' + this.labelWidth,
14913 html : this.fieldLabel
14917 cls : "col-md-" + (12 - this.labelWidth),
14924 } else if ( this.fieldLabel.length) {
14931 cls: 'control-label box-input-label',
14932 //cls : 'input-group-addon',
14933 html : this.fieldLabel
14943 Roo.log(" no label && no align");
14958 html: this.boxLabel
14965 inputEl: function ()
14967 return this.el.select('input.roo-radio',true).first();
14969 onClick : function()
14971 this.setChecked(true);
14974 setChecked : function(state,suppressEvent)
14977 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14978 v.dom.checked = false;
14982 this.checked = state;
14983 this.inputEl().dom.checked = state;
14985 if(suppressEvent !== true){
14986 this.fireEvent('check', this, state);
14989 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14993 getGroupValue : function()
14996 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14997 if(v.dom.checked == true){
14998 value = v.dom.value;
15006 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15007 * @return {Mixed} value The field value
15009 getValue : function(){
15010 return this.getGroupValue();
15016 //<script type="text/javascript">
15019 * Based Ext JS Library 1.1.1
15020 * Copyright(c) 2006-2007, Ext JS, LLC.
15026 * @class Roo.HtmlEditorCore
15027 * @extends Roo.Component
15028 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15030 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15033 Roo.HtmlEditorCore = function(config){
15036 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15039 * @event initialize
15040 * Fires when the editor is fully initialized (including the iframe)
15041 * @param {Roo.HtmlEditorCore} this
15046 * Fires when the editor is first receives the focus. Any insertion must wait
15047 * until after this event.
15048 * @param {Roo.HtmlEditorCore} this
15052 * @event beforesync
15053 * Fires before the textarea is updated with content from the editor iframe. Return false
15054 * to cancel the sync.
15055 * @param {Roo.HtmlEditorCore} this
15056 * @param {String} html
15060 * @event beforepush
15061 * Fires before the iframe editor is updated with content from the textarea. Return false
15062 * to cancel the push.
15063 * @param {Roo.HtmlEditorCore} this
15064 * @param {String} html
15069 * Fires when the textarea is updated with content from the editor iframe.
15070 * @param {Roo.HtmlEditorCore} this
15071 * @param {String} html
15076 * Fires when the iframe editor is updated with content from the textarea.
15077 * @param {Roo.HtmlEditorCore} this
15078 * @param {String} html
15083 * @event editorevent
15084 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15085 * @param {Roo.HtmlEditorCore} this
15093 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15097 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15103 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15108 * @cfg {Number} height (in pixels)
15112 * @cfg {Number} width (in pixels)
15117 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15120 stylesheets: false,
15125 // private properties
15126 validationEvent : false,
15128 initialized : false,
15130 sourceEditMode : false,
15131 onFocus : Roo.emptyFn,
15133 hideMode:'offsets',
15141 * Protected method that will not generally be called directly. It
15142 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15143 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15145 getDocMarkup : function(){
15148 Roo.log(this.stylesheets);
15150 // inherit styels from page...??
15151 if (this.stylesheets === false) {
15153 Roo.get(document.head).select('style').each(function(node) {
15154 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15157 Roo.get(document.head).select('link').each(function(node) {
15158 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15161 } else if (!this.stylesheets.length) {
15163 st = '<style type="text/css">' +
15164 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15167 Roo.each(this.stylesheets, function(s) {
15168 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15173 st += '<style type="text/css">' +
15174 'IMG { cursor: pointer } ' +
15178 return '<html><head>' + st +
15179 //<style type="text/css">' +
15180 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15182 ' </head><body class="roo-htmleditor-body"></body></html>';
15186 onRender : function(ct, position)
15189 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15190 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15193 this.el.dom.style.border = '0 none';
15194 this.el.dom.setAttribute('tabIndex', -1);
15195 this.el.addClass('x-hidden hide');
15199 if(Roo.isIE){ // fix IE 1px bogus margin
15200 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15204 this.frameId = Roo.id();
15208 var iframe = this.owner.wrap.createChild({
15210 cls: 'form-control', // bootstrap..
15212 name: this.frameId,
15213 frameBorder : 'no',
15214 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15219 this.iframe = iframe.dom;
15221 this.assignDocWin();
15223 this.doc.designMode = 'on';
15226 this.doc.write(this.getDocMarkup());
15230 var task = { // must defer to wait for browser to be ready
15232 //console.log("run task?" + this.doc.readyState);
15233 this.assignDocWin();
15234 if(this.doc.body || this.doc.readyState == 'complete'){
15236 this.doc.designMode="on";
15240 Roo.TaskMgr.stop(task);
15241 this.initEditor.defer(10, this);
15248 Roo.TaskMgr.start(task);
15255 onResize : function(w, h)
15257 Roo.log('resize: ' +w + ',' + h );
15258 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15262 if(typeof w == 'number'){
15264 this.iframe.style.width = w + 'px';
15266 if(typeof h == 'number'){
15268 this.iframe.style.height = h + 'px';
15270 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15277 * Toggles the editor between standard and source edit mode.
15278 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15280 toggleSourceEdit : function(sourceEditMode){
15282 this.sourceEditMode = sourceEditMode === true;
15284 if(this.sourceEditMode){
15286 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15289 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15290 //this.iframe.className = '';
15293 //this.setSize(this.owner.wrap.getSize());
15294 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15301 * Protected method that will not generally be called directly. If you need/want
15302 * custom HTML cleanup, this is the method you should override.
15303 * @param {String} html The HTML to be cleaned
15304 * return {String} The cleaned HTML
15306 cleanHtml : function(html){
15307 html = String(html);
15308 if(html.length > 5){
15309 if(Roo.isSafari){ // strip safari nonsense
15310 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15313 if(html == ' '){
15320 * HTML Editor -> Textarea
15321 * Protected method that will not generally be called directly. Syncs the contents
15322 * of the editor iframe with the textarea.
15324 syncValue : function(){
15325 if(this.initialized){
15326 var bd = (this.doc.body || this.doc.documentElement);
15327 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15328 var html = bd.innerHTML;
15330 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15331 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15333 html = '<div style="'+m[0]+'">' + html + '</div>';
15336 html = this.cleanHtml(html);
15337 // fix up the special chars.. normaly like back quotes in word...
15338 // however we do not want to do this with chinese..
15339 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15340 var cc = b.charCodeAt();
15342 (cc >= 0x4E00 && cc < 0xA000 ) ||
15343 (cc >= 0x3400 && cc < 0x4E00 ) ||
15344 (cc >= 0xf900 && cc < 0xfb00 )
15350 if(this.owner.fireEvent('beforesync', this, html) !== false){
15351 this.el.dom.value = html;
15352 this.owner.fireEvent('sync', this, html);
15358 * Protected method that will not generally be called directly. Pushes the value of the textarea
15359 * into the iframe editor.
15361 pushValue : function(){
15362 if(this.initialized){
15363 var v = this.el.dom.value.trim();
15365 // if(v.length < 1){
15369 if(this.owner.fireEvent('beforepush', this, v) !== false){
15370 var d = (this.doc.body || this.doc.documentElement);
15372 this.cleanUpPaste();
15373 this.el.dom.value = d.innerHTML;
15374 this.owner.fireEvent('push', this, v);
15380 deferFocus : function(){
15381 this.focus.defer(10, this);
15385 focus : function(){
15386 if(this.win && !this.sourceEditMode){
15393 assignDocWin: function()
15395 var iframe = this.iframe;
15398 this.doc = iframe.contentWindow.document;
15399 this.win = iframe.contentWindow;
15401 if (!Roo.get(this.frameId)) {
15404 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15405 this.win = Roo.get(this.frameId).dom.contentWindow;
15410 initEditor : function(){
15411 //console.log("INIT EDITOR");
15412 this.assignDocWin();
15416 this.doc.designMode="on";
15418 this.doc.write(this.getDocMarkup());
15421 var dbody = (this.doc.body || this.doc.documentElement);
15422 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
15423 // this copies styles from the containing element into thsi one..
15424 // not sure why we need all of this..
15425 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
15427 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
15428 //ss['background-attachment'] = 'fixed'; // w3c
15429 dbody.bgProperties = 'fixed'; // ie
15430 //Roo.DomHelper.applyStyles(dbody, ss);
15431 Roo.EventManager.on(this.doc, {
15432 //'mousedown': this.onEditorEvent,
15433 'mouseup': this.onEditorEvent,
15434 'dblclick': this.onEditorEvent,
15435 'click': this.onEditorEvent,
15436 'keyup': this.onEditorEvent,
15441 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
15443 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
15444 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
15446 this.initialized = true;
15448 this.owner.fireEvent('initialize', this);
15453 onDestroy : function(){
15459 //for (var i =0; i < this.toolbars.length;i++) {
15460 // // fixme - ask toolbars for heights?
15461 // this.toolbars[i].onDestroy();
15464 //this.wrap.dom.innerHTML = '';
15465 //this.wrap.remove();
15470 onFirstFocus : function(){
15472 this.assignDocWin();
15475 this.activated = true;
15478 if(Roo.isGecko){ // prevent silly gecko errors
15480 var s = this.win.getSelection();
15481 if(!s.focusNode || s.focusNode.nodeType != 3){
15482 var r = s.getRangeAt(0);
15483 r.selectNodeContents((this.doc.body || this.doc.documentElement));
15488 this.execCmd('useCSS', true);
15489 this.execCmd('styleWithCSS', false);
15492 this.owner.fireEvent('activate', this);
15496 adjustFont: function(btn){
15497 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
15498 //if(Roo.isSafari){ // safari
15501 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
15502 if(Roo.isSafari){ // safari
15503 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
15504 v = (v < 10) ? 10 : v;
15505 v = (v > 48) ? 48 : v;
15506 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
15511 v = Math.max(1, v+adjust);
15513 this.execCmd('FontSize', v );
15516 onEditorEvent : function(e){
15517 this.owner.fireEvent('editorevent', this, e);
15518 // this.updateToolbar();
15519 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
15522 insertTag : function(tg)
15524 // could be a bit smarter... -> wrap the current selected tRoo..
15525 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
15527 range = this.createRange(this.getSelection());
15528 var wrappingNode = this.doc.createElement(tg.toLowerCase());
15529 wrappingNode.appendChild(range.extractContents());
15530 range.insertNode(wrappingNode);
15537 this.execCmd("formatblock", tg);
15541 insertText : function(txt)
15545 var range = this.createRange();
15546 range.deleteContents();
15547 //alert(Sender.getAttribute('label'));
15549 range.insertNode(this.doc.createTextNode(txt));
15555 * Executes a Midas editor command on the editor document and performs necessary focus and
15556 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
15557 * @param {String} cmd The Midas command
15558 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15560 relayCmd : function(cmd, value){
15562 this.execCmd(cmd, value);
15563 this.owner.fireEvent('editorevent', this);
15564 //this.updateToolbar();
15565 this.owner.deferFocus();
15569 * Executes a Midas editor command directly on the editor document.
15570 * For visual commands, you should use {@link #relayCmd} instead.
15571 * <b>This should only be called after the editor is initialized.</b>
15572 * @param {String} cmd The Midas command
15573 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15575 execCmd : function(cmd, value){
15576 this.doc.execCommand(cmd, false, value === undefined ? null : value);
15583 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
15585 * @param {String} text | dom node..
15587 insertAtCursor : function(text)
15592 if(!this.activated){
15598 var r = this.doc.selection.createRange();
15609 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
15613 // from jquery ui (MIT licenced)
15615 var win = this.win;
15617 if (win.getSelection && win.getSelection().getRangeAt) {
15618 range = win.getSelection().getRangeAt(0);
15619 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
15620 range.insertNode(node);
15621 } else if (win.document.selection && win.document.selection.createRange) {
15622 // no firefox support
15623 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15624 win.document.selection.createRange().pasteHTML(txt);
15626 // no firefox support
15627 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15628 this.execCmd('InsertHTML', txt);
15637 mozKeyPress : function(e){
15639 var c = e.getCharCode(), cmd;
15642 c = String.fromCharCode(c).toLowerCase();
15656 this.cleanUpPaste.defer(100, this);
15664 e.preventDefault();
15672 fixKeys : function(){ // load time branching for fastest keydown performance
15674 return function(e){
15675 var k = e.getKey(), r;
15678 r = this.doc.selection.createRange();
15681 r.pasteHTML('    ');
15688 r = this.doc.selection.createRange();
15690 var target = r.parentElement();
15691 if(!target || target.tagName.toLowerCase() != 'li'){
15693 r.pasteHTML('<br />');
15699 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15700 this.cleanUpPaste.defer(100, this);
15706 }else if(Roo.isOpera){
15707 return function(e){
15708 var k = e.getKey();
15712 this.execCmd('InsertHTML','    ');
15715 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15716 this.cleanUpPaste.defer(100, this);
15721 }else if(Roo.isSafari){
15722 return function(e){
15723 var k = e.getKey();
15727 this.execCmd('InsertText','\t');
15731 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15732 this.cleanUpPaste.defer(100, this);
15740 getAllAncestors: function()
15742 var p = this.getSelectedNode();
15745 a.push(p); // push blank onto stack..
15746 p = this.getParentElement();
15750 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15754 a.push(this.doc.body);
15758 lastSelNode : false,
15761 getSelection : function()
15763 this.assignDocWin();
15764 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15767 getSelectedNode: function()
15769 // this may only work on Gecko!!!
15771 // should we cache this!!!!
15776 var range = this.createRange(this.getSelection()).cloneRange();
15779 var parent = range.parentElement();
15781 var testRange = range.duplicate();
15782 testRange.moveToElementText(parent);
15783 if (testRange.inRange(range)) {
15786 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15789 parent = parent.parentElement;
15794 // is ancestor a text element.
15795 var ac = range.commonAncestorContainer;
15796 if (ac.nodeType == 3) {
15797 ac = ac.parentNode;
15800 var ar = ac.childNodes;
15803 var other_nodes = [];
15804 var has_other_nodes = false;
15805 for (var i=0;i<ar.length;i++) {
15806 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15809 // fullly contained node.
15811 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15816 // probably selected..
15817 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15818 other_nodes.push(ar[i]);
15822 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15827 has_other_nodes = true;
15829 if (!nodes.length && other_nodes.length) {
15830 nodes= other_nodes;
15832 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15838 createRange: function(sel)
15840 // this has strange effects when using with
15841 // top toolbar - not sure if it's a great idea.
15842 //this.editor.contentWindow.focus();
15843 if (typeof sel != "undefined") {
15845 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15847 return this.doc.createRange();
15850 return this.doc.createRange();
15853 getParentElement: function()
15856 this.assignDocWin();
15857 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15859 var range = this.createRange(sel);
15862 var p = range.commonAncestorContainer;
15863 while (p.nodeType == 3) { // text node
15874 * Range intersection.. the hard stuff...
15878 * [ -- selected range --- ]
15882 * if end is before start or hits it. fail.
15883 * if start is after end or hits it fail.
15885 * if either hits (but other is outside. - then it's not
15891 // @see http://www.thismuchiknow.co.uk/?p=64.
15892 rangeIntersectsNode : function(range, node)
15894 var nodeRange = node.ownerDocument.createRange();
15896 nodeRange.selectNode(node);
15898 nodeRange.selectNodeContents(node);
15901 var rangeStartRange = range.cloneRange();
15902 rangeStartRange.collapse(true);
15904 var rangeEndRange = range.cloneRange();
15905 rangeEndRange.collapse(false);
15907 var nodeStartRange = nodeRange.cloneRange();
15908 nodeStartRange.collapse(true);
15910 var nodeEndRange = nodeRange.cloneRange();
15911 nodeEndRange.collapse(false);
15913 return rangeStartRange.compareBoundaryPoints(
15914 Range.START_TO_START, nodeEndRange) == -1 &&
15915 rangeEndRange.compareBoundaryPoints(
15916 Range.START_TO_START, nodeStartRange) == 1;
15920 rangeCompareNode : function(range, node)
15922 var nodeRange = node.ownerDocument.createRange();
15924 nodeRange.selectNode(node);
15926 nodeRange.selectNodeContents(node);
15930 range.collapse(true);
15932 nodeRange.collapse(true);
15934 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15935 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15937 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15939 var nodeIsBefore = ss == 1;
15940 var nodeIsAfter = ee == -1;
15942 if (nodeIsBefore && nodeIsAfter)
15944 if (!nodeIsBefore && nodeIsAfter)
15945 return 1; //right trailed.
15947 if (nodeIsBefore && !nodeIsAfter)
15948 return 2; // left trailed.
15953 // private? - in a new class?
15954 cleanUpPaste : function()
15956 // cleans up the whole document..
15957 Roo.log('cleanuppaste');
15959 this.cleanUpChildren(this.doc.body);
15960 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15961 if (clean != this.doc.body.innerHTML) {
15962 this.doc.body.innerHTML = clean;
15967 cleanWordChars : function(input) {// change the chars to hex code
15968 var he = Roo.HtmlEditorCore;
15970 var output = input;
15971 Roo.each(he.swapCodes, function(sw) {
15972 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15974 output = output.replace(swapper, sw[1]);
15981 cleanUpChildren : function (n)
15983 if (!n.childNodes.length) {
15986 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15987 this.cleanUpChild(n.childNodes[i]);
15994 cleanUpChild : function (node)
15997 //console.log(node);
15998 if (node.nodeName == "#text") {
15999 // clean up silly Windows -- stuff?
16002 if (node.nodeName == "#comment") {
16003 node.parentNode.removeChild(node);
16004 // clean up silly Windows -- stuff?
16008 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16010 node.parentNode.removeChild(node);
16015 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16017 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16018 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16020 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16021 // remove_keep_children = true;
16024 if (remove_keep_children) {
16025 this.cleanUpChildren(node);
16026 // inserts everything just before this node...
16027 while (node.childNodes.length) {
16028 var cn = node.childNodes[0];
16029 node.removeChild(cn);
16030 node.parentNode.insertBefore(cn, node);
16032 node.parentNode.removeChild(node);
16036 if (!node.attributes || !node.attributes.length) {
16037 this.cleanUpChildren(node);
16041 function cleanAttr(n,v)
16044 if (v.match(/^\./) || v.match(/^\//)) {
16047 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16050 if (v.match(/^#/)) {
16053 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16054 node.removeAttribute(n);
16058 function cleanStyle(n,v)
16060 if (v.match(/expression/)) { //XSS?? should we even bother..
16061 node.removeAttribute(n);
16064 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16065 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16068 var parts = v.split(/;/);
16071 Roo.each(parts, function(p) {
16072 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16076 var l = p.split(':').shift().replace(/\s+/g,'');
16077 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16079 if ( cblack.indexOf(l) > -1) {
16080 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16081 //node.removeAttribute(n);
16085 // only allow 'c whitelisted system attributes'
16086 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16087 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16088 //node.removeAttribute(n);
16098 if (clean.length) {
16099 node.setAttribute(n, clean.join(';'));
16101 node.removeAttribute(n);
16107 for (var i = node.attributes.length-1; i > -1 ; i--) {
16108 var a = node.attributes[i];
16111 if (a.name.toLowerCase().substr(0,2)=='on') {
16112 node.removeAttribute(a.name);
16115 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16116 node.removeAttribute(a.name);
16119 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16120 cleanAttr(a.name,a.value); // fixme..
16123 if (a.name == 'style') {
16124 cleanStyle(a.name,a.value);
16127 /// clean up MS crap..
16128 // tecnically this should be a list of valid class'es..
16131 if (a.name == 'class') {
16132 if (a.value.match(/^Mso/)) {
16133 node.className = '';
16136 if (a.value.match(/body/)) {
16137 node.className = '';
16148 this.cleanUpChildren(node);
16153 * Clean up MS wordisms...
16155 cleanWord : function(node)
16158 var cleanWordChildren = function()
16160 if (!node.childNodes.length) {
16163 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16164 _t.cleanWord(node.childNodes[i]);
16170 this.cleanWord(this.doc.body);
16173 if (node.nodeName == "#text") {
16174 // clean up silly Windows -- stuff?
16177 if (node.nodeName == "#comment") {
16178 node.parentNode.removeChild(node);
16179 // clean up silly Windows -- stuff?
16183 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16184 node.parentNode.removeChild(node);
16188 // remove - but keep children..
16189 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16190 while (node.childNodes.length) {
16191 var cn = node.childNodes[0];
16192 node.removeChild(cn);
16193 node.parentNode.insertBefore(cn, node);
16195 node.parentNode.removeChild(node);
16196 cleanWordChildren();
16200 if (node.className.length) {
16202 var cn = node.className.split(/\W+/);
16204 Roo.each(cn, function(cls) {
16205 if (cls.match(/Mso[a-zA-Z]+/)) {
16210 node.className = cna.length ? cna.join(' ') : '';
16212 node.removeAttribute("class");
16216 if (node.hasAttribute("lang")) {
16217 node.removeAttribute("lang");
16220 if (node.hasAttribute("style")) {
16222 var styles = node.getAttribute("style").split(";");
16224 Roo.each(styles, function(s) {
16225 if (!s.match(/:/)) {
16228 var kv = s.split(":");
16229 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16232 // what ever is left... we allow.
16235 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16236 if (!nstyle.length) {
16237 node.removeAttribute('style');
16241 cleanWordChildren();
16245 domToHTML : function(currentElement, depth, nopadtext) {
16247 depth = depth || 0;
16248 nopadtext = nopadtext || false;
16250 if (!currentElement) {
16251 return this.domToHTML(this.doc.body);
16254 //Roo.log(currentElement);
16256 var allText = false;
16257 var nodeName = currentElement.nodeName;
16258 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16260 if (nodeName == '#text') {
16261 return currentElement.nodeValue;
16266 if (nodeName != 'BODY') {
16269 // Prints the node tagName, such as <A>, <IMG>, etc
16272 for(i = 0; i < currentElement.attributes.length;i++) {
16274 var aname = currentElement.attributes.item(i).name;
16275 if (!currentElement.attributes.item(i).value.length) {
16278 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16281 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16290 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16293 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16298 // Traverse the tree
16300 var currentElementChild = currentElement.childNodes.item(i);
16301 var allText = true;
16302 var innerHTML = '';
16304 while (currentElementChild) {
16305 // Formatting code (indent the tree so it looks nice on the screen)
16306 var nopad = nopadtext;
16307 if (lastnode == 'SPAN') {
16311 if (currentElementChild.nodeName == '#text') {
16312 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16313 if (!nopad && toadd.length > 80) {
16314 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16316 innerHTML += toadd;
16319 currentElementChild = currentElement.childNodes.item(i);
16325 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16327 // Recursively traverse the tree structure of the child node
16328 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16329 lastnode = currentElementChild.nodeName;
16331 currentElementChild=currentElement.childNodes.item(i);
16337 // The remaining code is mostly for formatting the tree
16338 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16343 ret+= "</"+tagName+">";
16349 // hide stuff that is not compatible
16363 * @event specialkey
16367 * @cfg {String} fieldClass @hide
16370 * @cfg {String} focusClass @hide
16373 * @cfg {String} autoCreate @hide
16376 * @cfg {String} inputType @hide
16379 * @cfg {String} invalidClass @hide
16382 * @cfg {String} invalidText @hide
16385 * @cfg {String} msgFx @hide
16388 * @cfg {String} validateOnBlur @hide
16392 Roo.HtmlEditorCore.white = [
16393 'area', 'br', 'img', 'input', 'hr', 'wbr',
16395 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16396 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16397 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16398 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16399 'table', 'ul', 'xmp',
16401 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16404 'dir', 'menu', 'ol', 'ul', 'dl',
16410 Roo.HtmlEditorCore.black = [
16411 // 'embed', 'object', // enable - backend responsiblity to clean thiese
16413 'base', 'basefont', 'bgsound', 'blink', 'body',
16414 'frame', 'frameset', 'head', 'html', 'ilayer',
16415 'iframe', 'layer', 'link', 'meta', 'object',
16416 'script', 'style' ,'title', 'xml' // clean later..
16418 Roo.HtmlEditorCore.clean = [
16419 'script', 'style', 'title', 'xml'
16421 Roo.HtmlEditorCore.remove = [
16426 Roo.HtmlEditorCore.ablack = [
16430 Roo.HtmlEditorCore.aclean = [
16431 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
16435 Roo.HtmlEditorCore.pwhite= [
16436 'http', 'https', 'mailto'
16439 // white listed style attributes.
16440 Roo.HtmlEditorCore.cwhite= [
16441 // 'text-align', /// default is to allow most things..
16447 // black listed style attributes.
16448 Roo.HtmlEditorCore.cblack= [
16449 // 'font-size' -- this can be set by the project
16453 Roo.HtmlEditorCore.swapCodes =[
16472 * @class Roo.bootstrap.HtmlEditor
16473 * @extends Roo.bootstrap.TextArea
16474 * Bootstrap HtmlEditor class
16477 * Create a new HtmlEditor
16478 * @param {Object} config The config object
16481 Roo.bootstrap.HtmlEditor = function(config){
16482 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
16483 if (!this.toolbars) {
16484 this.toolbars = [];
16486 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
16489 * @event initialize
16490 * Fires when the editor is fully initialized (including the iframe)
16491 * @param {HtmlEditor} this
16496 * Fires when the editor is first receives the focus. Any insertion must wait
16497 * until after this event.
16498 * @param {HtmlEditor} this
16502 * @event beforesync
16503 * Fires before the textarea is updated with content from the editor iframe. Return false
16504 * to cancel the sync.
16505 * @param {HtmlEditor} this
16506 * @param {String} html
16510 * @event beforepush
16511 * Fires before the iframe editor is updated with content from the textarea. Return false
16512 * to cancel the push.
16513 * @param {HtmlEditor} this
16514 * @param {String} html
16519 * Fires when the textarea is updated with content from the editor iframe.
16520 * @param {HtmlEditor} this
16521 * @param {String} html
16526 * Fires when the iframe editor is updated with content from the textarea.
16527 * @param {HtmlEditor} this
16528 * @param {String} html
16532 * @event editmodechange
16533 * Fires when the editor switches edit modes
16534 * @param {HtmlEditor} this
16535 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
16537 editmodechange: true,
16539 * @event editorevent
16540 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16541 * @param {HtmlEditor} this
16545 * @event firstfocus
16546 * Fires when on first focus - needed by toolbars..
16547 * @param {HtmlEditor} this
16552 * Auto save the htmlEditor value as a file into Events
16553 * @param {HtmlEditor} this
16557 * @event savedpreview
16558 * preview the saved version of htmlEditor
16559 * @param {HtmlEditor} this
16566 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
16570 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
16575 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16580 * @cfg {Number} height (in pixels)
16584 * @cfg {Number} width (in pixels)
16589 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16592 stylesheets: false,
16597 // private properties
16598 validationEvent : false,
16600 initialized : false,
16603 onFocus : Roo.emptyFn,
16605 hideMode:'offsets',
16608 tbContainer : false,
16610 toolbarContainer :function() {
16611 return this.wrap.select('.x-html-editor-tb',true).first();
16615 * Protected method that will not generally be called directly. It
16616 * is called when the editor creates its toolbar. Override this method if you need to
16617 * add custom toolbar buttons.
16618 * @param {HtmlEditor} editor
16620 createToolbar : function(){
16622 Roo.log("create toolbars");
16624 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
16625 this.toolbars[0].render(this.toolbarContainer());
16629 // if (!editor.toolbars || !editor.toolbars.length) {
16630 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
16633 // for (var i =0 ; i < editor.toolbars.length;i++) {
16634 // editor.toolbars[i] = Roo.factory(
16635 // typeof(editor.toolbars[i]) == 'string' ?
16636 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
16637 // Roo.bootstrap.HtmlEditor);
16638 // editor.toolbars[i].init(editor);
16644 onRender : function(ct, position)
16646 // Roo.log("Call onRender: " + this.xtype);
16648 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
16650 this.wrap = this.inputEl().wrap({
16651 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16654 this.editorcore.onRender(ct, position);
16656 if (this.resizable) {
16657 this.resizeEl = new Roo.Resizable(this.wrap, {
16661 minHeight : this.height,
16662 height: this.height,
16663 handles : this.resizable,
16666 resize : function(r, w, h) {
16667 _t.onResize(w,h); // -something
16673 this.createToolbar(this);
16676 if(!this.width && this.resizable){
16677 this.setSize(this.wrap.getSize());
16679 if (this.resizeEl) {
16680 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16681 // should trigger onReize..
16687 onResize : function(w, h)
16689 Roo.log('resize: ' +w + ',' + h );
16690 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16694 if(this.inputEl() ){
16695 if(typeof w == 'number'){
16696 var aw = w - this.wrap.getFrameWidth('lr');
16697 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16700 if(typeof h == 'number'){
16701 var tbh = -11; // fixme it needs to tool bar size!
16702 for (var i =0; i < this.toolbars.length;i++) {
16703 // fixme - ask toolbars for heights?
16704 tbh += this.toolbars[i].el.getHeight();
16705 //if (this.toolbars[i].footer) {
16706 // tbh += this.toolbars[i].footer.el.getHeight();
16714 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16715 ah -= 5; // knock a few pixes off for look..
16716 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16720 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16721 this.editorcore.onResize(ew,eh);
16726 * Toggles the editor between standard and source edit mode.
16727 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16729 toggleSourceEdit : function(sourceEditMode)
16731 this.editorcore.toggleSourceEdit(sourceEditMode);
16733 if(this.editorcore.sourceEditMode){
16734 Roo.log('editor - showing textarea');
16737 // Roo.log(this.syncValue());
16739 this.inputEl().removeClass('hide');
16740 this.inputEl().dom.removeAttribute('tabIndex');
16741 this.inputEl().focus();
16743 Roo.log('editor - hiding textarea');
16745 // Roo.log(this.pushValue());
16748 this.inputEl().addClass('hide');
16749 this.inputEl().dom.setAttribute('tabIndex', -1);
16750 //this.deferFocus();
16753 if(this.resizable){
16754 this.setSize(this.wrap.getSize());
16757 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16760 // private (for BoxComponent)
16761 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16763 // private (for BoxComponent)
16764 getResizeEl : function(){
16768 // private (for BoxComponent)
16769 getPositionEl : function(){
16774 initEvents : function(){
16775 this.originalValue = this.getValue();
16779 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16782 // markInvalid : Roo.emptyFn,
16784 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16787 // clearInvalid : Roo.emptyFn,
16789 setValue : function(v){
16790 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16791 this.editorcore.pushValue();
16796 deferFocus : function(){
16797 this.focus.defer(10, this);
16801 focus : function(){
16802 this.editorcore.focus();
16808 onDestroy : function(){
16814 for (var i =0; i < this.toolbars.length;i++) {
16815 // fixme - ask toolbars for heights?
16816 this.toolbars[i].onDestroy();
16819 this.wrap.dom.innerHTML = '';
16820 this.wrap.remove();
16825 onFirstFocus : function(){
16826 //Roo.log("onFirstFocus");
16827 this.editorcore.onFirstFocus();
16828 for (var i =0; i < this.toolbars.length;i++) {
16829 this.toolbars[i].onFirstFocus();
16835 syncValue : function()
16837 this.editorcore.syncValue();
16840 pushValue : function()
16842 this.editorcore.pushValue();
16846 // hide stuff that is not compatible
16860 * @event specialkey
16864 * @cfg {String} fieldClass @hide
16867 * @cfg {String} focusClass @hide
16870 * @cfg {String} autoCreate @hide
16873 * @cfg {String} inputType @hide
16876 * @cfg {String} invalidClass @hide
16879 * @cfg {String} invalidText @hide
16882 * @cfg {String} msgFx @hide
16885 * @cfg {String} validateOnBlur @hide
16894 Roo.namespace('Roo.bootstrap.htmleditor');
16896 * @class Roo.bootstrap.HtmlEditorToolbar1
16901 new Roo.bootstrap.HtmlEditor({
16904 new Roo.bootstrap.HtmlEditorToolbar1({
16905 disable : { fonts: 1 , format: 1, ..., ... , ...],
16911 * @cfg {Object} disable List of elements to disable..
16912 * @cfg {Array} btns List of additional buttons.
16916 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16919 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16922 Roo.apply(this, config);
16924 // default disabled, based on 'good practice'..
16925 this.disable = this.disable || {};
16926 Roo.applyIf(this.disable, {
16929 specialElements : true
16931 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16933 this.editor = config.editor;
16934 this.editorcore = config.editor.editorcore;
16936 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16938 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16939 // dont call parent... till later.
16941 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16946 editorcore : false,
16951 "h1","h2","h3","h4","h5","h6",
16953 "abbr", "acronym", "address", "cite", "samp", "var",
16957 onRender : function(ct, position)
16959 // Roo.log("Call onRender: " + this.xtype);
16961 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16963 this.el.dom.style.marginBottom = '0';
16965 var editorcore = this.editorcore;
16966 var editor= this.editor;
16969 var btn = function(id,cmd , toggle, handler){
16971 var event = toggle ? 'toggle' : 'click';
16976 xns: Roo.bootstrap,
16979 enableToggle:toggle !== false,
16981 pressed : toggle ? false : null,
16984 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16985 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16994 xns: Roo.bootstrap,
16995 glyphicon : 'font',
16999 xns: Roo.bootstrap,
17003 Roo.each(this.formats, function(f) {
17004 style.menu.items.push({
17006 xns: Roo.bootstrap,
17007 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17012 editorcore.insertTag(this.tagname);
17019 children.push(style);
17022 btn('bold',false,true);
17023 btn('italic',false,true);
17024 btn('align-left', 'justifyleft',true);
17025 btn('align-center', 'justifycenter',true);
17026 btn('align-right' , 'justifyright',true);
17027 btn('link', false, false, function(btn) {
17028 //Roo.log("create link?");
17029 var url = prompt(this.createLinkText, this.defaultLinkValue);
17030 if(url && url != 'http:/'+'/'){
17031 this.editorcore.relayCmd('createlink', url);
17034 btn('list','insertunorderedlist',true);
17035 btn('pencil', false,true, function(btn){
17038 this.toggleSourceEdit(btn.pressed);
17044 xns: Roo.bootstrap,
17049 xns: Roo.bootstrap,
17054 cog.menu.items.push({
17056 xns: Roo.bootstrap,
17057 html : Clean styles,
17062 editorcore.insertTag(this.tagname);
17071 this.xtype = 'NavSimplebar';
17073 for(var i=0;i< children.length;i++) {
17075 this.buttons.add(this.addxtypeChild(children[i]));
17079 editor.on('editorevent', this.updateToolbar, this);
17081 onBtnClick : function(id)
17083 this.editorcore.relayCmd(id);
17084 this.editorcore.focus();
17088 * Protected method that will not generally be called directly. It triggers
17089 * a toolbar update by reading the markup state of the current selection in the editor.
17091 updateToolbar: function(){
17093 if(!this.editorcore.activated){
17094 this.editor.onFirstFocus(); // is this neeed?
17098 var btns = this.buttons;
17099 var doc = this.editorcore.doc;
17100 btns.get('bold').setActive(doc.queryCommandState('bold'));
17101 btns.get('italic').setActive(doc.queryCommandState('italic'));
17102 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17104 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17105 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17106 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17108 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17109 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17112 var ans = this.editorcore.getAllAncestors();
17113 if (this.formatCombo) {
17116 var store = this.formatCombo.store;
17117 this.formatCombo.setValue("");
17118 for (var i =0; i < ans.length;i++) {
17119 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17121 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17129 // hides menus... - so this cant be on a menu...
17130 Roo.bootstrap.MenuMgr.hideAll();
17132 Roo.bootstrap.MenuMgr.hideAll();
17133 //this.editorsyncValue();
17135 onFirstFocus: function() {
17136 this.buttons.each(function(item){
17140 toggleSourceEdit : function(sourceEditMode){
17143 if(sourceEditMode){
17144 Roo.log("disabling buttons");
17145 this.buttons.each( function(item){
17146 if(item.cmd != 'pencil'){
17152 Roo.log("enabling buttons");
17153 if(this.editorcore.initialized){
17154 this.buttons.each( function(item){
17160 Roo.log("calling toggole on editor");
17161 // tell the editor that it's been pressed..
17162 this.editor.toggleSourceEdit(sourceEditMode);
17172 * @class Roo.bootstrap.Table.AbstractSelectionModel
17173 * @extends Roo.util.Observable
17174 * Abstract base class for grid SelectionModels. It provides the interface that should be
17175 * implemented by descendant classes. This class should not be directly instantiated.
17178 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17179 this.locked = false;
17180 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17184 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17185 /** @ignore Called by the grid automatically. Do not call directly. */
17186 init : function(grid){
17192 * Locks the selections.
17195 this.locked = true;
17199 * Unlocks the selections.
17201 unlock : function(){
17202 this.locked = false;
17206 * Returns true if the selections are locked.
17207 * @return {Boolean}
17209 isLocked : function(){
17210 return this.locked;
17214 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17215 * @class Roo.bootstrap.Table.RowSelectionModel
17216 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17217 * It supports multiple selections and keyboard selection/navigation.
17219 * @param {Object} config
17222 Roo.bootstrap.Table.RowSelectionModel = function(config){
17223 Roo.apply(this, config);
17224 this.selections = new Roo.util.MixedCollection(false, function(o){
17229 this.lastActive = false;
17233 * @event selectionchange
17234 * Fires when the selection changes
17235 * @param {SelectionModel} this
17237 "selectionchange" : true,
17239 * @event afterselectionchange
17240 * Fires after the selection changes (eg. by key press or clicking)
17241 * @param {SelectionModel} this
17243 "afterselectionchange" : true,
17245 * @event beforerowselect
17246 * Fires when a row is selected being selected, return false to cancel.
17247 * @param {SelectionModel} this
17248 * @param {Number} rowIndex The selected index
17249 * @param {Boolean} keepExisting False if other selections will be cleared
17251 "beforerowselect" : true,
17254 * Fires when a row is selected.
17255 * @param {SelectionModel} this
17256 * @param {Number} rowIndex The selected index
17257 * @param {Roo.data.Record} r The record
17259 "rowselect" : true,
17261 * @event rowdeselect
17262 * Fires when a row is deselected.
17263 * @param {SelectionModel} this
17264 * @param {Number} rowIndex The selected index
17266 "rowdeselect" : true
17268 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17269 this.locked = false;
17272 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17274 * @cfg {Boolean} singleSelect
17275 * True to allow selection of only one row at a time (defaults to false)
17277 singleSelect : false,
17280 initEvents : function(){
17282 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17283 this.grid.on("mousedown", this.handleMouseDown, this);
17284 }else{ // allow click to work like normal
17285 this.grid.on("rowclick", this.handleDragableRowClick, this);
17288 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17289 "up" : function(e){
17291 this.selectPrevious(e.shiftKey);
17292 }else if(this.last !== false && this.lastActive !== false){
17293 var last = this.last;
17294 this.selectRange(this.last, this.lastActive-1);
17295 this.grid.getView().focusRow(this.lastActive);
17296 if(last !== false){
17300 this.selectFirstRow();
17302 this.fireEvent("afterselectionchange", this);
17304 "down" : function(e){
17306 this.selectNext(e.shiftKey);
17307 }else if(this.last !== false && this.lastActive !== false){
17308 var last = this.last;
17309 this.selectRange(this.last, this.lastActive+1);
17310 this.grid.getView().focusRow(this.lastActive);
17311 if(last !== false){
17315 this.selectFirstRow();
17317 this.fireEvent("afterselectionchange", this);
17322 var view = this.grid.view;
17323 view.on("refresh", this.onRefresh, this);
17324 view.on("rowupdated", this.onRowUpdated, this);
17325 view.on("rowremoved", this.onRemove, this);
17329 onRefresh : function(){
17330 var ds = this.grid.dataSource, i, v = this.grid.view;
17331 var s = this.selections;
17332 s.each(function(r){
17333 if((i = ds.indexOfId(r.id)) != -1){
17342 onRemove : function(v, index, r){
17343 this.selections.remove(r);
17347 onRowUpdated : function(v, index, r){
17348 if(this.isSelected(r)){
17349 v.onRowSelect(index);
17355 * @param {Array} records The records to select
17356 * @param {Boolean} keepExisting (optional) True to keep existing selections
17358 selectRecords : function(records, keepExisting){
17360 this.clearSelections();
17362 var ds = this.grid.dataSource;
17363 for(var i = 0, len = records.length; i < len; i++){
17364 this.selectRow(ds.indexOf(records[i]), true);
17369 * Gets the number of selected rows.
17372 getCount : function(){
17373 return this.selections.length;
17377 * Selects the first row in the grid.
17379 selectFirstRow : function(){
17384 * Select the last row.
17385 * @param {Boolean} keepExisting (optional) True to keep existing selections
17387 selectLastRow : function(keepExisting){
17388 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17392 * Selects the row immediately following the last selected row.
17393 * @param {Boolean} keepExisting (optional) True to keep existing selections
17395 selectNext : function(keepExisting){
17396 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17397 this.selectRow(this.last+1, keepExisting);
17398 this.grid.getView().focusRow(this.last);
17403 * Selects the row that precedes the last selected row.
17404 * @param {Boolean} keepExisting (optional) True to keep existing selections
17406 selectPrevious : function(keepExisting){
17408 this.selectRow(this.last-1, keepExisting);
17409 this.grid.getView().focusRow(this.last);
17414 * Returns the selected records
17415 * @return {Array} Array of selected records
17417 getSelections : function(){
17418 return [].concat(this.selections.items);
17422 * Returns the first selected record.
17425 getSelected : function(){
17426 return this.selections.itemAt(0);
17431 * Clears all selections.
17433 clearSelections : function(fast){
17434 if(this.locked) return;
17436 var ds = this.grid.dataSource;
17437 var s = this.selections;
17438 s.each(function(r){
17439 this.deselectRow(ds.indexOfId(r.id));
17443 this.selections.clear();
17450 * Selects all rows.
17452 selectAll : function(){
17453 if(this.locked) return;
17454 this.selections.clear();
17455 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17456 this.selectRow(i, true);
17461 * Returns True if there is a selection.
17462 * @return {Boolean}
17464 hasSelection : function(){
17465 return this.selections.length > 0;
17469 * Returns True if the specified row is selected.
17470 * @param {Number/Record} record The record or index of the record to check
17471 * @return {Boolean}
17473 isSelected : function(index){
17474 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17475 return (r && this.selections.key(r.id) ? true : false);
17479 * Returns True if the specified record id is selected.
17480 * @param {String} id The id of record to check
17481 * @return {Boolean}
17483 isIdSelected : function(id){
17484 return (this.selections.key(id) ? true : false);
17488 handleMouseDown : function(e, t){
17489 var view = this.grid.getView(), rowIndex;
17490 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17493 if(e.shiftKey && this.last !== false){
17494 var last = this.last;
17495 this.selectRange(last, rowIndex, e.ctrlKey);
17496 this.last = last; // reset the last
17497 view.focusRow(rowIndex);
17499 var isSelected = this.isSelected(rowIndex);
17500 if(e.button !== 0 && isSelected){
17501 view.focusRow(rowIndex);
17502 }else if(e.ctrlKey && isSelected){
17503 this.deselectRow(rowIndex);
17504 }else if(!isSelected){
17505 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17506 view.focusRow(rowIndex);
17509 this.fireEvent("afterselectionchange", this);
17512 handleDragableRowClick : function(grid, rowIndex, e)
17514 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17515 this.selectRow(rowIndex, false);
17516 grid.view.focusRow(rowIndex);
17517 this.fireEvent("afterselectionchange", this);
17522 * Selects multiple rows.
17523 * @param {Array} rows Array of the indexes of the row to select
17524 * @param {Boolean} keepExisting (optional) True to keep existing selections
17526 selectRows : function(rows, keepExisting){
17528 this.clearSelections();
17530 for(var i = 0, len = rows.length; i < len; i++){
17531 this.selectRow(rows[i], true);
17536 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17537 * @param {Number} startRow The index of the first row in the range
17538 * @param {Number} endRow The index of the last row in the range
17539 * @param {Boolean} keepExisting (optional) True to retain existing selections
17541 selectRange : function(startRow, endRow, keepExisting){
17542 if(this.locked) return;
17544 this.clearSelections();
17546 if(startRow <= endRow){
17547 for(var i = startRow; i <= endRow; i++){
17548 this.selectRow(i, true);
17551 for(var i = startRow; i >= endRow; i--){
17552 this.selectRow(i, true);
17558 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17559 * @param {Number} startRow The index of the first row in the range
17560 * @param {Number} endRow The index of the last row in the range
17562 deselectRange : function(startRow, endRow, preventViewNotify){
17563 if(this.locked) return;
17564 for(var i = startRow; i <= endRow; i++){
17565 this.deselectRow(i, preventViewNotify);
17571 * @param {Number} row The index of the row to select
17572 * @param {Boolean} keepExisting (optional) True to keep existing selections
17574 selectRow : function(index, keepExisting, preventViewNotify){
17575 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17576 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17577 if(!keepExisting || this.singleSelect){
17578 this.clearSelections();
17580 var r = this.grid.dataSource.getAt(index);
17581 this.selections.add(r);
17582 this.last = this.lastActive = index;
17583 if(!preventViewNotify){
17584 this.grid.getView().onRowSelect(index);
17586 this.fireEvent("rowselect", this, index, r);
17587 this.fireEvent("selectionchange", this);
17593 * @param {Number} row The index of the row to deselect
17595 deselectRow : function(index, preventViewNotify){
17596 if(this.locked) return;
17597 if(this.last == index){
17600 if(this.lastActive == index){
17601 this.lastActive = false;
17603 var r = this.grid.dataSource.getAt(index);
17604 this.selections.remove(r);
17605 if(!preventViewNotify){
17606 this.grid.getView().onRowDeselect(index);
17608 this.fireEvent("rowdeselect", this, index);
17609 this.fireEvent("selectionchange", this);
17613 restoreLast : function(){
17615 this.last = this._last;
17620 acceptsNav : function(row, col, cm){
17621 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17625 onEditorKey : function(field, e){
17626 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17631 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17633 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17635 }else if(k == e.ENTER && !e.ctrlKey){
17639 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17641 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17643 }else if(k == e.ESC){
17647 g.startEditing(newCell[0], newCell[1]);
17652 * Ext JS Library 1.1.1
17653 * Copyright(c) 2006-2007, Ext JS, LLC.
17655 * Originally Released Under LGPL - original licence link has changed is not relivant.
17658 * <script type="text/javascript">
17662 * @class Roo.bootstrap.PagingToolbar
17664 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17666 * Create a new PagingToolbar
17667 * @param {Object} config The config object
17669 Roo.bootstrap.PagingToolbar = function(config)
17671 // old args format still supported... - xtype is prefered..
17672 // created from xtype...
17673 var ds = config.dataSource;
17674 this.toolbarItems = [];
17675 if (config.items) {
17676 this.toolbarItems = config.items;
17677 // config.items = [];
17680 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17687 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17691 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17693 * @cfg {Roo.data.Store} dataSource
17694 * The underlying data store providing the paged data
17697 * @cfg {String/HTMLElement/Element} container
17698 * container The id or element that will contain the toolbar
17701 * @cfg {Boolean} displayInfo
17702 * True to display the displayMsg (defaults to false)
17705 * @cfg {Number} pageSize
17706 * The number of records to display per page (defaults to 20)
17710 * @cfg {String} displayMsg
17711 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17713 displayMsg : 'Displaying {0} - {1} of {2}',
17715 * @cfg {String} emptyMsg
17716 * The message to display when no records are found (defaults to "No data to display")
17718 emptyMsg : 'No data to display',
17720 * Customizable piece of the default paging text (defaults to "Page")
17723 beforePageText : "Page",
17725 * Customizable piece of the default paging text (defaults to "of %0")
17728 afterPageText : "of {0}",
17730 * Customizable piece of the default paging text (defaults to "First Page")
17733 firstText : "First Page",
17735 * Customizable piece of the default paging text (defaults to "Previous Page")
17738 prevText : "Previous Page",
17740 * Customizable piece of the default paging text (defaults to "Next Page")
17743 nextText : "Next Page",
17745 * Customizable piece of the default paging text (defaults to "Last Page")
17748 lastText : "Last Page",
17750 * Customizable piece of the default paging text (defaults to "Refresh")
17753 refreshText : "Refresh",
17757 onRender : function(ct, position)
17759 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17760 this.navgroup.parentId = this.id;
17761 this.navgroup.onRender(this.el, null);
17762 // add the buttons to the navgroup
17764 if(this.displayInfo){
17765 Roo.log(this.el.select('ul.navbar-nav',true).first());
17766 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
17767 this.displayEl = this.el.select('.x-paging-info', true).first();
17768 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
17769 // this.displayEl = navel.el.select('span',true).first();
17775 Roo.each(_this.buttons, function(e){
17776 Roo.factory(e).onRender(_this.el, null);
17780 Roo.each(_this.toolbarItems, function(e) {
17781 _this.navgroup.addItem(e);
17784 this.first = this.navgroup.addItem({
17785 tooltip: this.firstText,
17787 icon : 'fa fa-backward',
17789 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17792 this.prev = this.navgroup.addItem({
17793 tooltip: this.prevText,
17795 icon : 'fa fa-step-backward',
17797 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17799 //this.addSeparator();
17802 var field = this.navgroup.addItem( {
17804 cls : 'x-paging-position',
17806 html : this.beforePageText +
17807 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17808 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17811 this.field = field.el.select('input', true).first();
17812 this.field.on("keydown", this.onPagingKeydown, this);
17813 this.field.on("focus", function(){this.dom.select();});
17816 this.afterTextEl = field.el.select('.x-paging-after',true).first();
17817 //this.field.setHeight(18);
17818 //this.addSeparator();
17819 this.next = this.navgroup.addItem({
17820 tooltip: this.nextText,
17822 html : ' <i class="fa fa-step-forward">',
17824 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17826 this.last = this.navgroup.addItem({
17827 tooltip: this.lastText,
17828 icon : 'fa fa-forward',
17831 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17833 //this.addSeparator();
17834 this.loading = this.navgroup.addItem({
17835 tooltip: this.refreshText,
17836 icon: 'fa fa-refresh',
17838 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17844 updateInfo : function(){
17845 if(this.displayEl){
17846 var count = this.ds.getCount();
17847 var msg = count == 0 ?
17851 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17853 this.displayEl.update(msg);
17858 onLoad : function(ds, r, o){
17859 this.cursor = o.params ? o.params.start : 0;
17860 var d = this.getPageData(),
17864 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
17865 this.field.dom.value = ap;
17866 this.first.setDisabled(ap == 1);
17867 this.prev.setDisabled(ap == 1);
17868 this.next.setDisabled(ap == ps);
17869 this.last.setDisabled(ap == ps);
17870 this.loading.enable();
17875 getPageData : function(){
17876 var total = this.ds.getTotalCount();
17879 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17880 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17885 onLoadError : function(){
17886 this.loading.enable();
17890 onPagingKeydown : function(e){
17891 var k = e.getKey();
17892 var d = this.getPageData();
17894 var v = this.field.dom.value, pageNum;
17895 if(!v || isNaN(pageNum = parseInt(v, 10))){
17896 this.field.dom.value = d.activePage;
17899 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17900 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17903 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
17905 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17906 this.field.dom.value = pageNum;
17907 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17910 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17912 var v = this.field.dom.value, pageNum;
17913 var increment = (e.shiftKey) ? 10 : 1;
17914 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17916 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17917 this.field.dom.value = d.activePage;
17920 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17922 this.field.dom.value = parseInt(v, 10) + increment;
17923 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17924 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17931 beforeLoad : function(){
17933 this.loading.disable();
17938 onClick : function(which){
17945 ds.load({params:{start: 0, limit: this.pageSize}});
17948 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17951 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17954 var total = ds.getTotalCount();
17955 var extra = total % this.pageSize;
17956 var lastStart = extra ? (total - extra) : total-this.pageSize;
17957 ds.load({params:{start: lastStart, limit: this.pageSize}});
17960 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17966 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17967 * @param {Roo.data.Store} store The data store to unbind
17969 unbind : function(ds){
17970 ds.un("beforeload", this.beforeLoad, this);
17971 ds.un("load", this.onLoad, this);
17972 ds.un("loadexception", this.onLoadError, this);
17973 ds.un("remove", this.updateInfo, this);
17974 ds.un("add", this.updateInfo, this);
17975 this.ds = undefined;
17979 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17980 * @param {Roo.data.Store} store The data store to bind
17982 bind : function(ds){
17983 ds.on("beforeload", this.beforeLoad, this);
17984 ds.on("load", this.onLoad, this);
17985 ds.on("loadexception", this.onLoadError, this);
17986 ds.on("remove", this.updateInfo, this);
17987 ds.on("add", this.updateInfo, this);
17998 * @class Roo.bootstrap.MessageBar
17999 * @extends Roo.bootstrap.Component
18000 * Bootstrap MessageBar class
18001 * @cfg {String} html contents of the MessageBar
18002 * @cfg {String} weight (info | success | warning | danger) default info
18003 * @cfg {String} beforeClass insert the bar before the given class
18004 * @cfg {Boolean} closable (true | false) default false
18005 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18008 * Create a new Element
18009 * @param {Object} config The config object
18012 Roo.bootstrap.MessageBar = function(config){
18013 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18016 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18022 beforeClass: 'bootstrap-sticky-wrap',
18024 getAutoCreate : function(){
18028 cls: 'alert alert-dismissable alert-' + this.weight,
18033 html: this.html || ''
18039 cfg.cls += ' alert-messages-fixed';
18053 onRender : function(ct, position)
18055 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18058 var cfg = Roo.apply({}, this.getAutoCreate());
18062 cfg.cls += ' ' + this.cls;
18065 cfg.style = this.style;
18067 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18069 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18072 this.el.select('>button.close').on('click', this.hide, this);
18078 if (!this.rendered) {
18084 this.fireEvent('show', this);
18090 if (!this.rendered) {
18096 this.fireEvent('hide', this);
18099 update : function()
18101 // var e = this.el.dom.firstChild;
18103 // if(this.closable){
18104 // e = e.nextSibling;
18107 // e.data = this.html || '';
18109 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18125 * @class Roo.bootstrap.Graph
18126 * @extends Roo.bootstrap.Component
18127 * Bootstrap Graph class
18131 @cfg {String} graphtype bar | vbar | pie
18132 @cfg {number} g_x coodinator | centre x (pie)
18133 @cfg {number} g_y coodinator | centre y (pie)
18134 @cfg {number} g_r radius (pie)
18135 @cfg {number} g_height height of the chart (respected by all elements in the set)
18136 @cfg {number} g_width width of the chart (respected by all elements in the set)
18137 @cfg {Object} title The title of the chart
18140 -opts (object) options for the chart
18142 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18143 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18145 o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
18146 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18148 o stretch (boolean)
18150 -opts (object) options for the pie
18153 o startAngle (number)
18154 o endAngle (number)
18158 * Create a new Input
18159 * @param {Object} config The config object
18162 Roo.bootstrap.Graph = function(config){
18163 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18169 * The img click event for the img.
18170 * @param {Roo.EventObject} e
18176 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18187 //g_colors: this.colors,
18194 getAutoCreate : function(){
18205 onRender : function(ct,position){
18206 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18207 this.raphael = Raphael(this.el.dom);
18209 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18210 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18211 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18212 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18214 r.text(160, 10, "Single Series Chart").attr(txtattr);
18215 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18216 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18217 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18219 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18220 r.barchart(330, 10, 300, 220, data1);
18221 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18222 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18225 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18226 // r.barchart(30, 30, 560, 250, xdata, {
18227 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18228 // axis : "0 0 1 1",
18229 // axisxlabels : xdata
18230 // //yvalues : cols,
18233 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18235 // this.load(null,xdata,{
18236 // axis : "0 0 1 1",
18237 // axisxlabels : xdata
18242 load : function(graphtype,xdata,opts){
18243 this.raphael.clear();
18245 graphtype = this.graphtype;
18250 var r = this.raphael,
18251 fin = function () {
18252 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18254 fout = function () {
18255 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18260 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18263 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18266 opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18267 href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18269 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts);
18276 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18281 setTitle: function(o)
18286 initEvents: function() {
18289 this.el.on('click', this.onClick, this);
18293 onClick : function(e)
18295 Roo.log('img onclick');
18296 this.fireEvent('click', this, e);
18308 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18311 * @class Roo.bootstrap.dash.NumberBox
18312 * @extends Roo.bootstrap.Component
18313 * Bootstrap NumberBox class
18314 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18315 * @cfg {String} headline Box headline
18316 * @cfg {String} content Box content
18317 * @cfg {String} icon Box icon
18318 * @cfg {String} footer Footer text
18319 * @cfg {String} fhref Footer href
18322 * Create a new NumberBox
18323 * @param {Object} config The config object
18327 Roo.bootstrap.dash.NumberBox = function(config){
18328 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18332 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18342 getAutoCreate : function(){
18346 cls : 'small-box bg-' + this.bgcolor,
18354 cls : 'roo-headline',
18355 html : this.headline
18359 cls : 'roo-content',
18360 html : this.content
18374 cls : 'ion ' + this.icon
18383 cls : 'small-box-footer',
18384 href : this.fhref || '#',
18388 cfg.cn.push(footer);
18395 onRender : function(ct,position){
18396 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
18403 setHeadline: function (value)
18405 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
18409 initEvents: function()