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 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3400 if (this.disabled) {
3401 cfg.cls += ' disabled';
3404 if (this.href || this.html) {
3408 href : this.href || "#",
3409 html: this.html || ''
3413 // glyphicon and icon go before content..
3414 if (this.glyphicon || this.icon) {
3416 cfg.cn[0].html = '<i class="'+this.icon+'"></i> <span>' + cfg.cn[0].html + '</span>'
3418 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span> ' + cfg.cn[0].html;
3424 if (cfg.cn && this.menu) {
3426 cfg.cn[0].html += " <span class='caret'></span>";
3430 if (this.badge !== '') {
3432 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3440 initEvents: function() {
3441 // Roo.log('init events?');
3442 // Roo.log(this.el.dom);
3443 if (typeof (this.menu) != 'undefined') {
3444 this.menu.parentType = this.xtype;
3445 this.menu.triggerEl = this.el;
3446 this.addxtype(Roo.apply({}, this.menu));
3450 this.el.select('a',true).on('click', this.onClick, this);
3451 // at this point parent should be available..
3452 this.parent().register(this);
3455 onClick : function(e)
3458 if(this.preventDefault){
3461 if (this.disabled) {
3464 Roo.log("fire event clicked");
3465 if(this.fireEvent('click', this, e) === false){
3469 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3470 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3471 this.parent().setActiveItem(this);
3479 isActive: function () {
3482 setActive : function(state, fire)
3484 this.active = state;
3486 this.el.removeClass('active');
3487 } else if (!this.el.hasClass('active')) {
3488 this.el.addClass('active');
3491 this.fireEvent('changed', this, state);
3496 // this should not be here...
3497 setDisabled : function(state)
3499 this.disabled = state;
3501 this.el.removeClass('disabled');
3502 } else if (!this.el.hasClass('disabled')) {
3503 this.el.addClass('disabled');
3516 * <span> icon </span>
3517 * <span> text </span>
3518 * <span>badge </span>
3522 * @class Roo.bootstrap.NavSidebarItem
3523 * @extends Roo.bootstrap.NavItem
3524 * Bootstrap Navbar.NavSidebarItem class
3526 * Create a new Navbar Button
3527 * @param {Object} config The config object
3529 Roo.bootstrap.NavSidebarItem = function(config){
3530 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3535 * The raw click event for the entire grid.
3536 * @param {Roo.EventObject} e
3541 * Fires when the active item active state changes
3542 * @param {Roo.bootstrap.NavSidebarItem} this
3543 * @param {boolean} state the new state
3551 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3554 getAutoCreate : function(){
3559 href : this.href || '#',
3571 html : this.html || ''
3576 cfg.cls += ' active';
3580 if (this.glyphicon || this.icon) {
3581 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3582 a.cn.push({ tag : 'i', cls : c }) ;
3587 if (this.badge !== '') {
3588 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3592 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3593 a.cls += 'dropdown-toggle treeview' ;
3617 * @class Roo.bootstrap.Row
3618 * @extends Roo.bootstrap.Component
3619 * Bootstrap Row class (contains columns...)
3623 * @param {Object} config The config object
3626 Roo.bootstrap.Row = function(config){
3627 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3630 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3632 getAutoCreate : function(){
3651 * @class Roo.bootstrap.Element
3652 * @extends Roo.bootstrap.Component
3653 * Bootstrap Element class
3654 * @cfg {String} html contents of the element
3655 * @cfg {String} tag tag of the element
3656 * @cfg {String} cls class of the element
3659 * Create a new Element
3660 * @param {Object} config The config object
3663 Roo.bootstrap.Element = function(config){
3664 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3667 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3674 getAutoCreate : function(){
3699 * @class Roo.bootstrap.Pagination
3700 * @extends Roo.bootstrap.Component
3701 * Bootstrap Pagination class
3702 * @cfg {String} size xs | sm | md | lg
3703 * @cfg {Boolean} inverse false | true
3706 * Create a new Pagination
3707 * @param {Object} config The config object
3710 Roo.bootstrap.Pagination = function(config){
3711 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3714 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3720 getAutoCreate : function(){
3726 cfg.cls += ' inverse';
3732 cfg.cls += " " + this.cls;
3750 * @class Roo.bootstrap.PaginationItem
3751 * @extends Roo.bootstrap.Component
3752 * Bootstrap PaginationItem class
3753 * @cfg {String} html text
3754 * @cfg {String} href the link
3755 * @cfg {Boolean} preventDefault (true | false) default true
3756 * @cfg {Boolean} active (true | false) default false
3760 * Create a new PaginationItem
3761 * @param {Object} config The config object
3765 Roo.bootstrap.PaginationItem = function(config){
3766 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3771 * The raw click event for the entire grid.
3772 * @param {Roo.EventObject} e
3778 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3782 preventDefault: true,
3786 getAutoCreate : function(){
3792 href : this.href ? this.href : '#',
3793 html : this.html ? this.html : ''
3803 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3809 initEvents: function() {
3811 this.el.on('click', this.onClick, this);
3814 onClick : function(e)
3816 Roo.log('PaginationItem on click ');
3817 if(this.preventDefault){
3821 this.fireEvent('click', this, e);
3837 * @class Roo.bootstrap.Slider
3838 * @extends Roo.bootstrap.Component
3839 * Bootstrap Slider class
3842 * Create a new Slider
3843 * @param {Object} config The config object
3846 Roo.bootstrap.Slider = function(config){
3847 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3850 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3852 getAutoCreate : function(){
3856 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3860 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3872 * Ext JS Library 1.1.1
3873 * Copyright(c) 2006-2007, Ext JS, LLC.
3875 * Originally Released Under LGPL - original licence link has changed is not relivant.
3878 * <script type="text/javascript">
3883 * @class Roo.grid.ColumnModel
3884 * @extends Roo.util.Observable
3885 * This is the default implementation of a ColumnModel used by the Grid. It defines
3886 * the columns in the grid.
3889 var colModel = new Roo.grid.ColumnModel([
3890 {header: "Ticker", width: 60, sortable: true, locked: true},
3891 {header: "Company Name", width: 150, sortable: true},
3892 {header: "Market Cap.", width: 100, sortable: true},
3893 {header: "$ Sales", width: 100, sortable: true, renderer: money},
3894 {header: "Employees", width: 100, sortable: true, resizable: false}
3899 * The config options listed for this class are options which may appear in each
3900 * individual column definition.
3901 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
3903 * @param {Object} config An Array of column config objects. See this class's
3904 * config objects for details.
3906 Roo.grid.ColumnModel = function(config){
3908 * The config passed into the constructor
3910 this.config = config;
3913 // if no id, create one
3914 // if the column does not have a dataIndex mapping,
3915 // map it to the order it is in the config
3916 for(var i = 0, len = config.length; i < len; i++){
3918 if(typeof c.dataIndex == "undefined"){
3921 if(typeof c.renderer == "string"){
3922 c.renderer = Roo.util.Format[c.renderer];
3924 if(typeof c.id == "undefined"){
3927 if(c.editor && c.editor.xtype){
3928 c.editor = Roo.factory(c.editor, Roo.grid);
3930 if(c.editor && c.editor.isFormField){
3931 c.editor = new Roo.grid.GridEditor(c.editor);
3933 this.lookup[c.id] = c;
3937 * The width of columns which have no width specified (defaults to 100)
3940 this.defaultWidth = 100;
3943 * Default sortable of columns which have no sortable specified (defaults to false)
3946 this.defaultSortable = false;
3950 * @event widthchange
3951 * Fires when the width of a column changes.
3952 * @param {ColumnModel} this
3953 * @param {Number} columnIndex The column index
3954 * @param {Number} newWidth The new width
3956 "widthchange": true,
3958 * @event headerchange
3959 * Fires when the text of a header changes.
3960 * @param {ColumnModel} this
3961 * @param {Number} columnIndex The column index
3962 * @param {Number} newText The new header text
3964 "headerchange": true,
3966 * @event hiddenchange
3967 * Fires when a column is hidden or "unhidden".
3968 * @param {ColumnModel} this
3969 * @param {Number} columnIndex The column index
3970 * @param {Boolean} hidden true if hidden, false otherwise
3972 "hiddenchange": true,
3974 * @event columnmoved
3975 * Fires when a column is moved.
3976 * @param {ColumnModel} this
3977 * @param {Number} oldIndex
3978 * @param {Number} newIndex
3980 "columnmoved" : true,
3982 * @event columlockchange
3983 * Fires when a column's locked state is changed
3984 * @param {ColumnModel} this
3985 * @param {Number} colIndex
3986 * @param {Boolean} locked true if locked
3988 "columnlockchange" : true
3990 Roo.grid.ColumnModel.superclass.constructor.call(this);
3992 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
3994 * @cfg {String} header The header text to display in the Grid view.
3997 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
3998 * {@link Roo.data.Record} definition from which to draw the column's value. If not
3999 * specified, the column's index is used as an index into the Record's data Array.
4002 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
4003 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
4006 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
4007 * Defaults to the value of the {@link #defaultSortable} property.
4008 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
4011 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
4014 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
4017 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
4020 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
4023 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
4024 * given the cell's data value. See {@link #setRenderer}. If not specified, the
4025 * default renderer uses the raw data value.
4028 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
4031 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
4035 * Returns the id of the column at the specified index.
4036 * @param {Number} index The column index
4037 * @return {String} the id
4039 getColumnId : function(index){
4040 return this.config[index].id;
4044 * Returns the column for a specified id.
4045 * @param {String} id The column id
4046 * @return {Object} the column
4048 getColumnById : function(id){
4049 return this.lookup[id];
4054 * Returns the column for a specified dataIndex.
4055 * @param {String} dataIndex The column dataIndex
4056 * @return {Object|Boolean} the column or false if not found
4058 getColumnByDataIndex: function(dataIndex){
4059 var index = this.findColumnIndex(dataIndex);
4060 return index > -1 ? this.config[index] : false;
4064 * Returns the index for a specified column id.
4065 * @param {String} id The column id
4066 * @return {Number} the index, or -1 if not found
4068 getIndexById : function(id){
4069 for(var i = 0, len = this.config.length; i < len; i++){
4070 if(this.config[i].id == id){
4078 * Returns the index for a specified column dataIndex.
4079 * @param {String} dataIndex The column dataIndex
4080 * @return {Number} the index, or -1 if not found
4083 findColumnIndex : function(dataIndex){
4084 for(var i = 0, len = this.config.length; i < len; i++){
4085 if(this.config[i].dataIndex == dataIndex){
4093 moveColumn : function(oldIndex, newIndex){
4094 var c = this.config[oldIndex];
4095 this.config.splice(oldIndex, 1);
4096 this.config.splice(newIndex, 0, c);
4097 this.dataMap = null;
4098 this.fireEvent("columnmoved", this, oldIndex, newIndex);
4101 isLocked : function(colIndex){
4102 return this.config[colIndex].locked === true;
4105 setLocked : function(colIndex, value, suppressEvent){
4106 if(this.isLocked(colIndex) == value){
4109 this.config[colIndex].locked = value;
4111 this.fireEvent("columnlockchange", this, colIndex, value);
4115 getTotalLockedWidth : function(){
4117 for(var i = 0; i < this.config.length; i++){
4118 if(this.isLocked(i) && !this.isHidden(i)){
4119 this.totalWidth += this.getColumnWidth(i);
4125 getLockedCount : function(){
4126 for(var i = 0, len = this.config.length; i < len; i++){
4127 if(!this.isLocked(i)){
4134 * Returns the number of columns.
4137 getColumnCount : function(visibleOnly){
4138 if(visibleOnly === true){
4140 for(var i = 0, len = this.config.length; i < len; i++){
4141 if(!this.isHidden(i)){
4147 return this.config.length;
4151 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
4152 * @param {Function} fn
4153 * @param {Object} scope (optional)
4154 * @return {Array} result
4156 getColumnsBy : function(fn, scope){
4158 for(var i = 0, len = this.config.length; i < len; i++){
4159 var c = this.config[i];
4160 if(fn.call(scope||this, c, i) === true){
4168 * Returns true if the specified column is sortable.
4169 * @param {Number} col The column index
4172 isSortable : function(col){
4173 if(typeof this.config[col].sortable == "undefined"){
4174 return this.defaultSortable;
4176 return this.config[col].sortable;
4180 * Returns the rendering (formatting) function defined for the column.
4181 * @param {Number} col The column index.
4182 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
4184 getRenderer : function(col){
4185 if(!this.config[col].renderer){
4186 return Roo.grid.ColumnModel.defaultRenderer;
4188 return this.config[col].renderer;
4192 * Sets the rendering (formatting) function for a column.
4193 * @param {Number} col The column index
4194 * @param {Function} fn The function to use to process the cell's raw data
4195 * to return HTML markup for the grid view. The render function is called with
4196 * the following parameters:<ul>
4197 * <li>Data value.</li>
4198 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
4199 * <li>css A CSS style string to apply to the table cell.</li>
4200 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
4201 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
4202 * <li>Row index</li>
4203 * <li>Column index</li>
4204 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
4206 setRenderer : function(col, fn){
4207 this.config[col].renderer = fn;
4211 * Returns the width for the specified column.
4212 * @param {Number} col The column index
4215 getColumnWidth : function(col){
4216 return this.config[col].width * 1 || this.defaultWidth;
4220 * Sets the width for a column.
4221 * @param {Number} col The column index
4222 * @param {Number} width The new width
4224 setColumnWidth : function(col, width, suppressEvent){
4225 this.config[col].width = width;
4226 this.totalWidth = null;
4228 this.fireEvent("widthchange", this, col, width);
4233 * Returns the total width of all columns.
4234 * @param {Boolean} includeHidden True to include hidden column widths
4237 getTotalWidth : function(includeHidden){
4238 if(!this.totalWidth){
4239 this.totalWidth = 0;
4240 for(var i = 0, len = this.config.length; i < len; i++){
4241 if(includeHidden || !this.isHidden(i)){
4242 this.totalWidth += this.getColumnWidth(i);
4246 return this.totalWidth;
4250 * Returns the header for the specified column.
4251 * @param {Number} col The column index
4254 getColumnHeader : function(col){
4255 return this.config[col].header;
4259 * Sets the header for a column.
4260 * @param {Number} col The column index
4261 * @param {String} header The new header
4263 setColumnHeader : function(col, header){
4264 this.config[col].header = header;
4265 this.fireEvent("headerchange", this, col, header);
4269 * Returns the tooltip for the specified column.
4270 * @param {Number} col The column index
4273 getColumnTooltip : function(col){
4274 return this.config[col].tooltip;
4277 * Sets the tooltip for a column.
4278 * @param {Number} col The column index
4279 * @param {String} tooltip The new tooltip
4281 setColumnTooltip : function(col, tooltip){
4282 this.config[col].tooltip = tooltip;
4286 * Returns the dataIndex for the specified column.
4287 * @param {Number} col The column index
4290 getDataIndex : function(col){
4291 return this.config[col].dataIndex;
4295 * Sets the dataIndex for a column.
4296 * @param {Number} col The column index
4297 * @param {Number} dataIndex The new dataIndex
4299 setDataIndex : function(col, dataIndex){
4300 this.config[col].dataIndex = dataIndex;
4306 * Returns true if the cell is editable.
4307 * @param {Number} colIndex The column index
4308 * @param {Number} rowIndex The row index
4311 isCellEditable : function(colIndex, rowIndex){
4312 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
4316 * Returns the editor defined for the cell/column.
4317 * return false or null to disable editing.
4318 * @param {Number} colIndex The column index
4319 * @param {Number} rowIndex The row index
4322 getCellEditor : function(colIndex, rowIndex){
4323 return this.config[colIndex].editor;
4327 * Sets if a column is editable.
4328 * @param {Number} col The column index
4329 * @param {Boolean} editable True if the column is editable
4331 setEditable : function(col, editable){
4332 this.config[col].editable = editable;
4337 * Returns true if the column is hidden.
4338 * @param {Number} colIndex The column index
4341 isHidden : function(colIndex){
4342 return this.config[colIndex].hidden;
4347 * Returns true if the column width cannot be changed
4349 isFixed : function(colIndex){
4350 return this.config[colIndex].fixed;
4354 * Returns true if the column can be resized
4357 isResizable : function(colIndex){
4358 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
4361 * Sets if a column is hidden.
4362 * @param {Number} colIndex The column index
4363 * @param {Boolean} hidden True if the column is hidden
4365 setHidden : function(colIndex, hidden){
4366 this.config[colIndex].hidden = hidden;
4367 this.totalWidth = null;
4368 this.fireEvent("hiddenchange", this, colIndex, hidden);
4372 * Sets the editor for a column.
4373 * @param {Number} col The column index
4374 * @param {Object} editor The editor object
4376 setEditor : function(col, editor){
4377 this.config[col].editor = editor;
4381 Roo.grid.ColumnModel.defaultRenderer = function(value){
4382 if(typeof value == "string" && value.length < 1){
4388 // Alias for backwards compatibility
4389 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
4392 * Ext JS Library 1.1.1
4393 * Copyright(c) 2006-2007, Ext JS, LLC.
4395 * Originally Released Under LGPL - original licence link has changed is not relivant.
4398 * <script type="text/javascript">
4402 * @class Roo.LoadMask
4403 * A simple utility class for generically masking elements while loading data. If the element being masked has
4404 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
4405 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
4406 * element's UpdateManager load indicator and will be destroyed after the initial load.
4408 * Create a new LoadMask
4409 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
4410 * @param {Object} config The config object
4412 Roo.LoadMask = function(el, config){
4413 this.el = Roo.get(el);
4414 Roo.apply(this, config);
4416 this.store.on('beforeload', this.onBeforeLoad, this);
4417 this.store.on('load', this.onLoad, this);
4418 this.store.on('loadexception', this.onLoadException, this);
4419 this.removeMask = false;
4421 var um = this.el.getUpdateManager();
4422 um.showLoadIndicator = false; // disable the default indicator
4423 um.on('beforeupdate', this.onBeforeLoad, this);
4424 um.on('update', this.onLoad, this);
4425 um.on('failure', this.onLoad, this);
4426 this.removeMask = true;
4430 Roo.LoadMask.prototype = {
4432 * @cfg {Boolean} removeMask
4433 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
4434 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
4438 * The text to display in a centered loading message box (defaults to 'Loading...')
4442 * @cfg {String} msgCls
4443 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
4445 msgCls : 'x-mask-loading',
4448 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
4454 * Disables the mask to prevent it from being displayed
4456 disable : function(){
4457 this.disabled = true;
4461 * Enables the mask so that it can be displayed
4463 enable : function(){
4464 this.disabled = false;
4467 onLoadException : function()
4471 if (typeof(arguments[3]) != 'undefined') {
4472 Roo.MessageBox.alert("Error loading",arguments[3]);
4476 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
4477 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
4486 this.el.unmask(this.removeMask);
4491 this.el.unmask(this.removeMask);
4495 onBeforeLoad : function(){
4497 this.el.mask(this.msg, this.msgCls);
4502 destroy : function(){
4504 this.store.un('beforeload', this.onBeforeLoad, this);
4505 this.store.un('load', this.onLoad, this);
4506 this.store.un('loadexception', this.onLoadException, this);
4508 var um = this.el.getUpdateManager();
4509 um.un('beforeupdate', this.onBeforeLoad, this);
4510 um.un('update', this.onLoad, this);
4511 um.un('failure', this.onLoad, this);
4522 * @class Roo.bootstrap.Table
4523 * @extends Roo.bootstrap.Component
4524 * Bootstrap Table class
4525 * @cfg {String} cls table class
4526 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4527 * @cfg {String} bgcolor Specifies the background color for a table
4528 * @cfg {Number} border Specifies whether the table cells should have borders or not
4529 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4530 * @cfg {Number} cellspacing Specifies the space between cells
4531 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4532 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4533 * @cfg {String} sortable Specifies that the table should be sortable
4534 * @cfg {String} summary Specifies a summary of the content of a table
4535 * @cfg {Number} width Specifies the width of a table
4536 * @cfg {String} layout table layout (auto | fixed | initial | inherit)
4538 * @cfg {boolean} striped Should the rows be alternative striped
4539 * @cfg {boolean} bordered Add borders to the table
4540 * @cfg {boolean} hover Add hover highlighting
4541 * @cfg {boolean} condensed Format condensed
4542 * @cfg {boolean} responsive Format condensed
4543 * @cfg {Boolean} loadMask (true|false) default false
4544 * @cfg {Boolean} tfoot (true|false) generate tfoot, default true
4545 * @cfg {Boolean} thead (true|false) generate thead, default true
4546 * @cfg {Boolean} RowSelection (true|false) default false
4547 * @cfg {Boolean} CellSelection (true|false) default false
4549 * @cfg {Roo.bootstrap.PagingToolbar} footer a paging toolbar
4553 * Create a new Table
4554 * @param {Object} config The config object
4557 Roo.bootstrap.Table = function(config){
4558 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4561 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4562 this.sm = this.selModel;
4563 this.sm.xmodule = this.xmodule || false;
4565 if (this.cm && typeof(this.cm.config) == 'undefined') {
4566 this.colModel = new Roo.grid.ColumnModel(this.cm);
4567 this.cm = this.colModel;
4568 this.cm.xmodule = this.xmodule || false;
4571 this.store= Roo.factory(this.store, Roo.data);
4572 this.ds = this.store;
4573 this.ds.xmodule = this.xmodule || false;
4576 if (this.footer && this.store) {
4577 this.footer.dataSource = this.ds;
4578 this.footer = Roo.factory(this.footer);
4585 * Fires when a cell is clicked
4586 * @param {Roo.bootstrap.Table} this
4587 * @param {Roo.Element} el
4588 * @param {Number} rowIndex
4589 * @param {Number} columnIndex
4590 * @param {Roo.EventObject} e
4594 * @event celldblclick
4595 * Fires when a cell is double clicked
4596 * @param {Roo.bootstrap.Table} this
4597 * @param {Roo.Element} el
4598 * @param {Number} rowIndex
4599 * @param {Number} columnIndex
4600 * @param {Roo.EventObject} e
4602 "celldblclick" : true,
4605 * Fires when a row is clicked
4606 * @param {Roo.bootstrap.Table} this
4607 * @param {Roo.Element} el
4608 * @param {Number} rowIndex
4609 * @param {Roo.EventObject} e
4613 * @event rowdblclick
4614 * Fires when a row is double clicked
4615 * @param {Roo.bootstrap.Table} this
4616 * @param {Roo.Element} el
4617 * @param {Number} rowIndex
4618 * @param {Roo.EventObject} e
4620 "rowdblclick" : true,
4623 * Fires when a row is rendered, so you can change add a style to it.
4624 * @param {Roo.bootstrap.Table} this
4625 * @param {Object} rowcfg contains record rowIndex colIndex and rowClass - set rowClass to add a style.
4632 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4656 RowSelection : false,
4657 CellSelection : false,
4661 getAutoCreate : function(){
4662 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4671 cfg.cls += ' table-striped';
4675 cfg.cls += ' table-hover';
4677 if (this.bordered) {
4678 cfg.cls += ' table-bordered';
4680 if (this.condensed) {
4681 cfg.cls += ' table-condensed';
4683 if (this.responsive) {
4684 cfg.cls += ' table-responsive';
4688 cfg.cls+= ' ' +this.cls;
4691 // this lot should be simplifed...
4694 cfg.align=this.align;
4697 cfg.bgcolor=this.bgcolor;
4700 cfg.border=this.border;
4702 if (this.cellpadding) {
4703 cfg.cellpadding=this.cellpadding;
4705 if (this.cellspacing) {
4706 cfg.cellspacing=this.cellspacing;
4709 cfg.frame=this.frame;
4712 cfg.rules=this.rules;
4714 if (this.sortable) {
4715 cfg.sortable=this.sortable;
4718 cfg.summary=this.summary;
4721 cfg.width=this.width;
4724 cfg.style = (typeof(cfg.style) == 'undefined') ? ('table-layout:' + this.layout + ';') : (cfg.style + ('table-layout:' + this.layout + ';'));
4727 if(this.store || this.cm){
4729 cfg.cn.push(this.renderHeader());
4732 cfg.cn.push(this.renderBody());
4735 cfg.cn.push(this.renderFooter());
4738 cfg.cls+= ' TableGrid';
4741 return { cn : [ cfg ] };
4744 initEvents : function()
4746 if(!this.store || !this.cm){
4750 Roo.log('initEvents with ds!!!!');
4754 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4755 e.on('click', _this.sort, _this);
4758 this.el.on("click", this.onClick, this);
4759 this.el.on("dblclick", this.onDblClick, this);
4761 this.parent().el.setStyle('position', 'relative');
4763 this.footer.parentId = this.id;
4764 this.footer.onRender(this.el.select('tfoot tr td').first(), null);
4767 this.maskEl = new Roo.LoadMask(this.el, { store : this.ds, msgCls: 'roo-el-mask-msg' });
4769 this.store.on('load', this.onLoad, this);
4770 this.store.on('beforeload', this.onBeforeLoad, this);
4774 onClick : function(e, el)
4776 var cell = Roo.get(el);
4777 var row = cell.findParent('tr', false, true);
4778 var cellIndex = cell.dom.cellIndex;
4779 var rowIndex = row.dom.rowIndex;
4781 if(this.CellSelection){
4782 this.fireEvent('cellclick', this, cell, rowIndex, cellIndex, e);
4785 if(this.RowSelection){
4786 this.fireEvent('rowclick', this, row, rowIndex, e);
4792 onDblClick : function(e,el)
4794 var cell = Roo.get(el);;
4795 var row = cell.findParent('tr', false, true);
4796 var cellIndex = cell.dom.cellIndex;
4797 var rowIndex = row.dom.rowIndex;
4799 if(this.CellSelection){
4800 this.fireEvent('celldblclick', this, cell, rowIndex, cellIndex, e);
4803 if(this.RowSelection){
4804 this.fireEvent('rowdblclick', this, row, rowIndex, e);
4808 sort : function(e,el)
4810 var col = Roo.get(el)
4812 if(!col.hasClass('sortable')){
4816 var sort = col.attr('sort');
4819 if(col.hasClass('glyphicon-arrow-up')){
4823 this.store.sortInfo = {field : sort, direction : dir};
4826 Roo.log("calling footer first");
4827 this.footer.onClick('first');
4830 this.store.load({ params : { start : 0 } });
4834 renderHeader : function()
4843 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4845 var config = cm.config[i];
4847 if(typeof(config.hidden) != 'undefined' && config.hidden){
4854 html: cm.getColumnHeader(i)
4857 if(typeof(config.dataIndex) != 'undefined'){
4858 c.sort = config.dataIndex;
4861 if(typeof(config.sortable) != 'undefined' && config.sortable){
4865 // if(typeof(config.align) != 'undefined' && config.align.length){
4866 // c.style += ' text-align:' + config.align + ';';
4869 if(typeof(config.width) != 'undefined'){
4870 c.style += ' width:' + config.width + 'px;';
4879 renderBody : function()
4889 colspan : this.cm.getColumnCount()
4899 renderFooter : function()
4909 colspan : this.cm.getColumnCount()
4921 Roo.log('ds onload');
4927 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4928 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4930 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4931 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4934 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4935 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4939 var tbody = this.el.select('tbody', true).first();
4943 if(this.store.getCount() > 0){
4944 this.store.data.each(function(d,rowIndex){
4950 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4951 var config = cm.config[i];
4953 if(typeof(config.hidden) != 'undefined' && config.hidden){
4957 var renderer = cm.getRenderer(i);
4961 if(typeof(renderer) !== 'undefined'){
4962 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4965 if(typeof(value) === 'object'){
4974 rowIndex : rowIndex,
4979 _this.fireEvent('rowclass', this, rowcfg);
4984 cls : rowcfg.rowClass,
4986 html: (typeof(value) === 'object') ? '' : value
4989 if(typeof(config.align) != 'undefined' && config.align.length){
4990 td.style += ' text-align:' + config.align + ';';
4993 if(typeof(config.width) != 'undefined'){
4994 td.style += ' width:' + config.width + 'px;';
5002 tbody.createChild(row);
5010 Roo.each(renders, function(r){
5011 _this.renderColumn(r);
5015 //if(this.loadMask){
5016 // this.maskEl.hide();
5020 onBeforeLoad : function()
5022 //Roo.log('ds onBeforeLoad');
5026 //if(this.loadMask){
5027 // this.maskEl.show();
5033 this.el.select('tbody', true).first().dom.innerHTML = '';
5036 getSelectionModel : function(){
5038 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
5040 return this.selModel;
5043 renderColumn : function(r)
5047 var t = r.cfg.render(r.container);
5050 Roo.each(r.cfg.cn, function(c){
5052 container: t.getChildContainer(),
5055 _this.renderColumn(child);
5072 * @class Roo.bootstrap.TableCell
5073 * @extends Roo.bootstrap.Component
5074 * Bootstrap TableCell class
5075 * @cfg {String} html cell contain text
5076 * @cfg {String} cls cell class
5077 * @cfg {String} tag cell tag (td|th) default td
5078 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
5079 * @cfg {String} align Aligns the content in a cell
5080 * @cfg {String} axis Categorizes cells
5081 * @cfg {String} bgcolor Specifies the background color of a cell
5082 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5083 * @cfg {Number} colspan Specifies the number of columns a cell should span
5084 * @cfg {String} headers Specifies one or more header cells a cell is related to
5085 * @cfg {Number} height Sets the height of a cell
5086 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
5087 * @cfg {Number} rowspan Sets the number of rows a cell should span
5088 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
5089 * @cfg {String} valign Vertical aligns the content in a cell
5090 * @cfg {Number} width Specifies the width of a cell
5093 * Create a new TableCell
5094 * @param {Object} config The config object
5097 Roo.bootstrap.TableCell = function(config){
5098 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
5101 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
5121 getAutoCreate : function(){
5122 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
5142 cfg.align=this.align
5148 cfg.bgcolor=this.bgcolor
5151 cfg.charoff=this.charoff
5154 cfg.colspan=this.colspan
5157 cfg.headers=this.headers
5160 cfg.height=this.height
5163 cfg.nowrap=this.nowrap
5166 cfg.rowspan=this.rowspan
5169 cfg.scope=this.scope
5172 cfg.valign=this.valign
5175 cfg.width=this.width
5194 * @class Roo.bootstrap.TableRow
5195 * @extends Roo.bootstrap.Component
5196 * Bootstrap TableRow class
5197 * @cfg {String} cls row class
5198 * @cfg {String} align Aligns the content in a table row
5199 * @cfg {String} bgcolor Specifies a background color for a table row
5200 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
5201 * @cfg {String} valign Vertical aligns the content in a table row
5204 * Create a new TableRow
5205 * @param {Object} config The config object
5208 Roo.bootstrap.TableRow = function(config){
5209 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
5212 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
5220 getAutoCreate : function(){
5221 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
5231 cfg.align = this.align;
5234 cfg.bgcolor = this.bgcolor;
5237 cfg.charoff = this.charoff;
5240 cfg.valign = this.valign;
5258 * @class Roo.bootstrap.TableBody
5259 * @extends Roo.bootstrap.Component
5260 * Bootstrap TableBody class
5261 * @cfg {String} cls element class
5262 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
5263 * @cfg {String} align Aligns the content inside the element
5264 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
5265 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
5268 * Create a new TableBody
5269 * @param {Object} config The config object
5272 Roo.bootstrap.TableBody = function(config){
5273 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
5276 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
5284 getAutoCreate : function(){
5285 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
5299 cfg.align = this.align;
5302 cfg.charoff = this.charoff;
5305 cfg.valign = this.valign;
5312 // initEvents : function()
5319 // this.store = Roo.factory(this.store, Roo.data);
5320 // this.store.on('load', this.onLoad, this);
5322 // this.store.load();
5326 // onLoad: function ()
5328 // this.fireEvent('load', this);
5338 * Ext JS Library 1.1.1
5339 * Copyright(c) 2006-2007, Ext JS, LLC.
5341 * Originally Released Under LGPL - original licence link has changed is not relivant.
5344 * <script type="text/javascript">
5347 // as we use this in bootstrap.
5348 Roo.namespace('Roo.form');
5350 * @class Roo.form.Action
5351 * Internal Class used to handle form actions
5353 * @param {Roo.form.BasicForm} el The form element or its id
5354 * @param {Object} config Configuration options
5359 // define the action interface
5360 Roo.form.Action = function(form, options){
5362 this.options = options || {};
5365 * Client Validation Failed
5368 Roo.form.Action.CLIENT_INVALID = 'client';
5370 * Server Validation Failed
5373 Roo.form.Action.SERVER_INVALID = 'server';
5375 * Connect to Server Failed
5378 Roo.form.Action.CONNECT_FAILURE = 'connect';
5380 * Reading Data from Server Failed
5383 Roo.form.Action.LOAD_FAILURE = 'load';
5385 Roo.form.Action.prototype = {
5387 failureType : undefined,
5388 response : undefined,
5392 run : function(options){
5397 success : function(response){
5402 handleResponse : function(response){
5406 // default connection failure
5407 failure : function(response){
5409 this.response = response;
5410 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5411 this.form.afterAction(this, false);
5414 processResponse : function(response){
5415 this.response = response;
5416 if(!response.responseText){
5419 this.result = this.handleResponse(response);
5423 // utility functions used internally
5424 getUrl : function(appendParams){
5425 var url = this.options.url || this.form.url || this.form.el.dom.action;
5427 var p = this.getParams();
5429 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
5435 getMethod : function(){
5436 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
5439 getParams : function(){
5440 var bp = this.form.baseParams;
5441 var p = this.options.params;
5443 if(typeof p == "object"){
5444 p = Roo.urlEncode(Roo.applyIf(p, bp));
5445 }else if(typeof p == 'string' && bp){
5446 p += '&' + Roo.urlEncode(bp);
5449 p = Roo.urlEncode(bp);
5454 createCallback : function(){
5456 success: this.success,
5457 failure: this.failure,
5459 timeout: (this.form.timeout*1000),
5460 upload: this.form.fileUpload ? this.success : undefined
5465 Roo.form.Action.Submit = function(form, options){
5466 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
5469 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
5472 haveProgress : false,
5473 uploadComplete : false,
5475 // uploadProgress indicator.
5476 uploadProgress : function()
5478 if (!this.form.progressUrl) {
5482 if (!this.haveProgress) {
5483 Roo.MessageBox.progress("Uploading", "Uploading");
5485 if (this.uploadComplete) {
5486 Roo.MessageBox.hide();
5490 this.haveProgress = true;
5492 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
5494 var c = new Roo.data.Connection();
5496 url : this.form.progressUrl,
5501 success : function(req){
5502 //console.log(data);
5506 rdata = Roo.decode(req.responseText)
5508 Roo.log("Invalid data from server..");
5512 if (!rdata || !rdata.success) {
5514 Roo.MessageBox.alert(Roo.encode(rdata));
5517 var data = rdata.data;
5519 if (this.uploadComplete) {
5520 Roo.MessageBox.hide();
5525 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
5526 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
5529 this.uploadProgress.defer(2000,this);
5532 failure: function(data) {
5533 Roo.log('progress url failed ');
5544 // run get Values on the form, so it syncs any secondary forms.
5545 this.form.getValues();
5547 var o = this.options;
5548 var method = this.getMethod();
5549 var isPost = method == 'POST';
5550 if(o.clientValidation === false || this.form.isValid()){
5552 if (this.form.progressUrl) {
5553 this.form.findField('UPLOAD_IDENTIFIER').setValue(
5554 (new Date() * 1) + '' + Math.random());
5559 Roo.Ajax.request(Roo.apply(this.createCallback(), {
5560 form:this.form.el.dom,
5561 url:this.getUrl(!isPost),
5563 params:isPost ? this.getParams() : null,
5564 isUpload: this.form.fileUpload
5567 this.uploadProgress();
5569 }else if (o.clientValidation !== false){ // client validation failed
5570 this.failureType = Roo.form.Action.CLIENT_INVALID;
5571 this.form.afterAction(this, false);
5575 success : function(response)
5577 this.uploadComplete= true;
5578 if (this.haveProgress) {
5579 Roo.MessageBox.hide();
5583 var result = this.processResponse(response);
5584 if(result === true || result.success){
5585 this.form.afterAction(this, true);
5589 this.form.markInvalid(result.errors);
5590 this.failureType = Roo.form.Action.SERVER_INVALID;
5592 this.form.afterAction(this, false);
5594 failure : function(response)
5596 this.uploadComplete= true;
5597 if (this.haveProgress) {
5598 Roo.MessageBox.hide();
5601 this.response = response;
5602 this.failureType = Roo.form.Action.CONNECT_FAILURE;
5603 this.form.afterAction(this, false);
5606 handleResponse : function(response){
5607 if(this.form.errorReader){
5608 var rs = this.form.errorReader.read(response);
5611 for(var i = 0, len = rs.records.length; i < len; i++) {
5612 var r = rs.records[i];
5616 if(errors.length < 1){
5620 success : rs.success,
5626 ret = Roo.decode(response.responseText);
5630 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
5640 Roo.form.Action.Load = function(form, options){
5641 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
5642 this.reader = this.form.reader;
5645 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
5650 Roo.Ajax.request(Roo.apply(
5651 this.createCallback(), {
5652 method:this.getMethod(),
5653 url:this.getUrl(false),
5654 params:this.getParams()
5658 success : function(response){
5660 var result = this.processResponse(response);
5661 if(result === true || !result.success || !result.data){
5662 this.failureType = Roo.form.Action.LOAD_FAILURE;
5663 this.form.afterAction(this, false);
5666 this.form.clearInvalid();
5667 this.form.setValues(result.data);
5668 this.form.afterAction(this, true);
5671 handleResponse : function(response){
5672 if(this.form.reader){
5673 var rs = this.form.reader.read(response);
5674 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5676 success : rs.success,
5680 return Roo.decode(response.responseText);
5684 Roo.form.Action.ACTION_TYPES = {
5685 'load' : Roo.form.Action.Load,
5686 'submit' : Roo.form.Action.Submit
5695 * @class Roo.bootstrap.Form
5696 * @extends Roo.bootstrap.Component
5697 * Bootstrap Form class
5698 * @cfg {String} method GET | POST (default POST)
5699 * @cfg {String} labelAlign top | left (default top)
5700 * @cfg {String} align left | right - for navbars
5705 * @param {Object} config The config object
5709 Roo.bootstrap.Form = function(config){
5710 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5713 * @event clientvalidation
5714 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5715 * @param {Form} this
5716 * @param {Boolean} valid true if the form has passed client-side validation
5718 clientvalidation: true,
5720 * @event beforeaction
5721 * Fires before any action is performed. Return false to cancel the action.
5722 * @param {Form} this
5723 * @param {Action} action The action to be performed
5727 * @event actionfailed
5728 * Fires when an action fails.
5729 * @param {Form} this
5730 * @param {Action} action The action that failed
5732 actionfailed : true,
5734 * @event actioncomplete
5735 * Fires when an action is completed.
5736 * @param {Form} this
5737 * @param {Action} action The action that completed
5739 actioncomplete : true
5744 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5747 * @cfg {String} method
5748 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5753 * The URL to use for form actions if one isn't supplied in the action options.
5756 * @cfg {Boolean} fileUpload
5757 * Set to true if this form is a file upload.
5761 * @cfg {Object} baseParams
5762 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5766 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5770 * @cfg {Sting} align (left|right) for navbar forms
5775 activeAction : null,
5778 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5779 * element by passing it or its id or mask the form itself by passing in true.
5782 waitMsgTarget : false,
5787 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5788 * element by passing it or its id or mask the form itself by passing in true.
5792 getAutoCreate : function(){
5796 method : this.method || 'POST',
5797 id : this.id || Roo.id(),
5800 if (this.parent().xtype.match(/^Nav/)) {
5801 cfg.cls = 'navbar-form navbar-' + this.align;
5805 if (this.labelAlign == 'left' ) {
5806 cfg.cls += ' form-horizontal';
5812 initEvents : function()
5814 this.el.on('submit', this.onSubmit, this);
5815 this.el.on('keypress', function(e) {
5816 if (e.getCharCode() != 13) {
5825 onSubmit : function(e){
5830 * Returns true if client-side validation on the form is successful.
5833 isValid : function(){
5834 var items = this.getItems();
5836 items.each(function(f){
5845 * Returns true if any fields in this form have changed since their original load.
5848 isDirty : function(){
5850 var items = this.getItems();
5851 items.each(function(f){
5861 * Performs a predefined action (submit or load) or custom actions you define on this form.
5862 * @param {String} actionName The name of the action type
5863 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5864 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5865 * accept other config options):
5867 Property Type Description
5868 ---------------- --------------- ----------------------------------------------------------------------------------
5869 url String The url for the action (defaults to the form's url)
5870 method String The form method to use (defaults to the form's method, or POST if not defined)
5871 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5872 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5873 validate the form on the client (defaults to false)
5875 * @return {BasicForm} this
5877 doAction : function(action, options){
5878 if(typeof action == 'string'){
5879 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5881 if(this.fireEvent('beforeaction', this, action) !== false){
5882 this.beforeAction(action);
5883 action.run.defer(100, action);
5889 beforeAction : function(action){
5890 var o = action.options;
5892 // not really supported yet.. ??
5894 //if(this.waitMsgTarget === true){
5895 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5896 //}else if(this.waitMsgTarget){
5897 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5898 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5900 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5906 afterAction : function(action, success){
5907 this.activeAction = null;
5908 var o = action.options;
5910 //if(this.waitMsgTarget === true){
5912 //}else if(this.waitMsgTarget){
5913 // this.waitMsgTarget.unmask();
5915 // Roo.MessageBox.updateProgress(1);
5916 // Roo.MessageBox.hide();
5923 Roo.callback(o.success, o.scope, [this, action]);
5924 this.fireEvent('actioncomplete', this, action);
5928 // failure condition..
5929 // we have a scenario where updates need confirming.
5930 // eg. if a locking scenario exists..
5931 // we look for { errors : { needs_confirm : true }} in the response.
5933 (typeof(action.result) != 'undefined') &&
5934 (typeof(action.result.errors) != 'undefined') &&
5935 (typeof(action.result.errors.needs_confirm) != 'undefined')
5938 Roo.log("not supported yet");
5941 Roo.MessageBox.confirm(
5942 "Change requires confirmation",
5943 action.result.errorMsg,
5948 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5958 Roo.callback(o.failure, o.scope, [this, action]);
5959 // show an error message if no failed handler is set..
5960 if (!this.hasListener('actionfailed')) {
5961 Roo.log("need to add dialog support");
5963 Roo.MessageBox.alert("Error",
5964 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5965 action.result.errorMsg :
5966 "Saving Failed, please check your entries or try again"
5971 this.fireEvent('actionfailed', this, action);
5976 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5977 * @param {String} id The value to search for
5980 findField : function(id){
5981 var items = this.getItems();
5982 var field = items.get(id);
5984 items.each(function(f){
5985 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5992 return field || null;
5995 * Mark fields in this form invalid in bulk.
5996 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5997 * @return {BasicForm} this
5999 markInvalid : function(errors){
6000 if(errors instanceof Array){
6001 for(var i = 0, len = errors.length; i < len; i++){
6002 var fieldError = errors[i];
6003 var f = this.findField(fieldError.id);
6005 f.markInvalid(fieldError.msg);
6011 if(typeof errors[id] != 'function' && (field = this.findField(id))){
6012 field.markInvalid(errors[id]);
6016 //Roo.each(this.childForms || [], function (f) {
6017 // f.markInvalid(errors);
6024 * Set values for fields in this form in bulk.
6025 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
6026 * @return {BasicForm} this
6028 setValues : function(values){
6029 if(values instanceof Array){ // array of objects
6030 for(var i = 0, len = values.length; i < len; i++){
6032 var f = this.findField(v.id);
6034 f.setValue(v.value);
6035 if(this.trackResetOnLoad){
6036 f.originalValue = f.getValue();
6040 }else{ // object hash
6043 if(typeof values[id] != 'function' && (field = this.findField(id))){
6045 if (field.setFromData &&
6047 field.displayField &&
6048 // combos' with local stores can
6049 // be queried via setValue()
6050 // to set their value..
6051 (field.store && !field.store.isLocal)
6055 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
6056 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
6057 field.setFromData(sd);
6060 field.setValue(values[id]);
6064 if(this.trackResetOnLoad){
6065 field.originalValue = field.getValue();
6071 //Roo.each(this.childForms || [], function (f) {
6072 // f.setValues(values);
6079 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
6080 * they are returned as an array.
6081 * @param {Boolean} asString
6084 getValues : function(asString){
6085 //if (this.childForms) {
6086 // copy values from the child forms
6087 // Roo.each(this.childForms, function (f) {
6088 // this.setValues(f.getValues());
6094 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
6095 if(asString === true){
6098 return Roo.urlDecode(fs);
6102 * Returns the fields in this form as an object with key/value pairs.
6103 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
6106 getFieldValues : function(with_hidden)
6108 var items = this.getItems();
6110 items.each(function(f){
6114 var v = f.getValue();
6115 if (f.inputType =='radio') {
6116 if (typeof(ret[f.getName()]) == 'undefined') {
6117 ret[f.getName()] = ''; // empty..
6120 if (!f.el.dom.checked) {
6128 // not sure if this supported any more..
6129 if ((typeof(v) == 'object') && f.getRawValue) {
6130 v = f.getRawValue() ; // dates..
6132 // combo boxes where name != hiddenName...
6133 if (f.name != f.getName()) {
6134 ret[f.name] = f.getRawValue();
6136 ret[f.getName()] = v;
6143 * Clears all invalid messages in this form.
6144 * @return {BasicForm} this
6146 clearInvalid : function(){
6147 var items = this.getItems();
6149 items.each(function(f){
6160 * @return {BasicForm} this
6163 var items = this.getItems();
6164 items.each(function(f){
6168 Roo.each(this.childForms || [], function (f) {
6175 getItems : function()
6177 var r=new Roo.util.MixedCollection(false, function(o){
6178 return o.id || (o.id = Roo.id());
6180 var iter = function(el) {
6187 Roo.each(el.items,function(e) {
6206 * Ext JS Library 1.1.1
6207 * Copyright(c) 2006-2007, Ext JS, LLC.
6209 * Originally Released Under LGPL - original licence link has changed is not relivant.
6212 * <script type="text/javascript">
6215 * @class Roo.form.VTypes
6216 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
6219 Roo.form.VTypes = function(){
6220 // closure these in so they are only created once.
6221 var alpha = /^[a-zA-Z_]+$/;
6222 var alphanum = /^[a-zA-Z0-9_]+$/;
6223 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
6224 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
6226 // All these messages and functions are configurable
6229 * The function used to validate email addresses
6230 * @param {String} value The email address
6232 'email' : function(v){
6233 return email.test(v);
6236 * The error text to display when the email validation function returns false
6239 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
6241 * The keystroke filter mask to be applied on email input
6244 'emailMask' : /[a-z0-9_\.\-@]/i,
6247 * The function used to validate URLs
6248 * @param {String} value The URL
6250 'url' : function(v){
6254 * The error text to display when the url validation function returns false
6257 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
6260 * The function used to validate alpha values
6261 * @param {String} value The value
6263 'alpha' : function(v){
6264 return alpha.test(v);
6267 * The error text to display when the alpha validation function returns false
6270 'alphaText' : 'This field should only contain letters and _',
6272 * The keystroke filter mask to be applied on alpha input
6275 'alphaMask' : /[a-z_]/i,
6278 * The function used to validate alphanumeric values
6279 * @param {String} value The value
6281 'alphanum' : function(v){
6282 return alphanum.test(v);
6285 * The error text to display when the alphanumeric validation function returns false
6288 'alphanumText' : 'This field should only contain letters, numbers and _',
6290 * The keystroke filter mask to be applied on alphanumeric input
6293 'alphanumMask' : /[a-z0-9_]/i
6303 * @class Roo.bootstrap.Input
6304 * @extends Roo.bootstrap.Component
6305 * Bootstrap Input class
6306 * @cfg {Boolean} disabled is it disabled
6307 * @cfg {String} fieldLabel - the label associated
6308 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
6309 * @cfg {String} name name of the input
6310 * @cfg {string} fieldLabel - the label associated
6311 * @cfg {string} inputType - input / file submit ...
6312 * @cfg {string} placeholder - placeholder to put in text.
6313 * @cfg {string} before - input group add on before
6314 * @cfg {string} after - input group add on after
6315 * @cfg {string} size - (lg|sm) or leave empty..
6316 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
6317 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
6318 * @cfg {Number} md colspan out of 12 for computer-sized screens
6319 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
6320 * @cfg {string} value default value of the input
6321 * @cfg {Number} labelWidth set the width of label (0-12)
6322 * @cfg {String} labelAlign (top|left)
6323 * @cfg {Boolean} readOnly Specifies that the field should be read-only
6324 * @cfg {String} align (left|center|right) Default left
6328 * Create a new Input
6329 * @param {Object} config The config object
6332 Roo.bootstrap.Input = function(config){
6333 Roo.bootstrap.Input.superclass.constructor.call(this, config);
6338 * Fires when this field receives input focus.
6339 * @param {Roo.form.Field} this
6344 * Fires when this field loses input focus.
6345 * @param {Roo.form.Field} this
6350 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
6351 * {@link Roo.EventObject#getKey} to determine which key was pressed.
6352 * @param {Roo.form.Field} this
6353 * @param {Roo.EventObject} e The event object
6358 * Fires just before the field blurs if the field value has changed.
6359 * @param {Roo.form.Field} this
6360 * @param {Mixed} newValue The new value
6361 * @param {Mixed} oldValue The original value
6366 * Fires after the field has been marked as invalid.
6367 * @param {Roo.form.Field} this
6368 * @param {String} msg The validation message
6373 * Fires after the field has been validated with no errors.
6374 * @param {Roo.form.Field} this
6379 * Fires after the key up
6380 * @param {Roo.form.Field} this
6381 * @param {Roo.EventObject} e The event Object
6387 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
6389 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
6390 automatic validation (defaults to "keyup").
6392 validationEvent : "keyup",
6394 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
6396 validateOnBlur : true,
6398 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
6400 validationDelay : 250,
6402 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
6404 focusClass : "x-form-focus", // not needed???
6408 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
6410 invalidClass : "has-error",
6413 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
6415 selectOnFocus : false,
6418 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
6422 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
6427 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
6429 disableKeyFilter : false,
6432 * @cfg {Boolean} disabled True to disable the field (defaults to false).
6436 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
6440 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
6442 blankText : "This field is required",
6445 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
6449 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
6451 maxLength : Number.MAX_VALUE,
6453 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
6455 minLengthText : "The minimum length for this field is {0}",
6457 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
6459 maxLengthText : "The maximum length for this field is {0}",
6463 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
6464 * If available, this function will be called only after the basic validators all return true, and will be passed the
6465 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
6469 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
6470 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
6471 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
6475 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
6499 parentLabelAlign : function()
6502 while (parent.parent()) {
6503 parent = parent.parent();
6504 if (typeof(parent.labelAlign) !='undefined') {
6505 return parent.labelAlign;
6512 getAutoCreate : function(){
6514 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6520 if(this.inputType != 'hidden'){
6521 cfg.cls = 'form-group' //input-group
6527 type : this.inputType,
6529 cls : 'form-control',
6530 placeholder : this.placeholder || ''
6535 input.style = (typeof(input.style) == 'undefined') ? ('text-align:' + this.align) : (input.style + 'text-align:' + this.align);
6538 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6539 input.maxLength = this.maxLength;
6542 if (this.disabled) {
6543 input.disabled=true;
6546 if (this.readOnly) {
6547 input.readonly=true;
6551 input.name = this.name;
6554 input.cls += ' input-' + this.size;
6557 ['xs','sm','md','lg'].map(function(size){
6558 if (settings[size]) {
6559 cfg.cls += ' col-' + size + '-' + settings[size];
6563 var inputblock = input;
6565 if (this.before || this.after) {
6568 cls : 'input-group',
6571 if (this.before && typeof(this.before) == 'string') {
6573 inputblock.cn.push({
6575 cls : 'roo-input-before input-group-addon',
6579 if (this.before && typeof(this.before) == 'object') {
6580 this.before = Roo.factory(this.before);
6581 Roo.log(this.before);
6582 inputblock.cn.push({
6584 cls : 'roo-input-before input-group-' +
6585 (this.before.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6589 inputblock.cn.push(input);
6591 if (this.after && typeof(this.after) == 'string') {
6592 inputblock.cn.push({
6594 cls : 'roo-input-after input-group-addon',
6598 if (this.after && typeof(this.after) == 'object') {
6599 this.after = Roo.factory(this.after);
6600 Roo.log(this.after);
6601 inputblock.cn.push({
6603 cls : 'roo-input-after input-group-' +
6604 (this.after.xtype == 'Button' ? 'btn' : 'addon') //?? what about checkboxes - that looks like a bit of a hack thought?
6609 if (align ==='left' && this.fieldLabel.length) {
6610 Roo.log("left and has label");
6616 cls : 'control-label col-sm-' + this.labelWidth,
6617 html : this.fieldLabel
6621 cls : "col-sm-" + (12 - this.labelWidth),
6628 } else if ( this.fieldLabel.length) {
6634 //cls : 'input-group-addon',
6635 html : this.fieldLabel
6645 Roo.log(" no label && no align");
6654 Roo.log('input-parentType: ' + this.parentType);
6656 if (this.parentType === 'Navbar' && this.parent().bar) {
6657 cfg.cls += ' navbar-form';
6665 * return the real input element.
6667 inputEl: function ()
6669 return this.el.select('input.form-control',true).first();
6671 setDisabled : function(v)
6673 var i = this.inputEl().dom;
6675 i.removeAttribute('disabled');
6679 i.setAttribute('disabled','true');
6681 initEvents : function()
6684 this.inputEl().on("keydown" , this.fireKey, this);
6685 this.inputEl().on("focus", this.onFocus, this);
6686 this.inputEl().on("blur", this.onBlur, this);
6688 this.inputEl().relayEvent('keyup', this);
6690 // reference to original value for reset
6691 this.originalValue = this.getValue();
6692 //Roo.form.TextField.superclass.initEvents.call(this);
6693 if(this.validationEvent == 'keyup'){
6694 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
6695 this.inputEl().on('keyup', this.filterValidation, this);
6697 else if(this.validationEvent !== false){
6698 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
6701 if(this.selectOnFocus){
6702 this.on("focus", this.preFocus, this);
6705 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6706 this.inputEl().on("keypress", this.filterKeys, this);
6709 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6710 this.el.on("click", this.autoSize, this);
6713 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6714 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6717 if (typeof(this.before) == 'object') {
6718 this.before.render(this.el.select('.roo-input-before',true).first());
6720 if (typeof(this.after) == 'object') {
6721 this.after.render(this.el.select('.roo-input-after',true).first());
6726 filterValidation : function(e){
6727 if(!e.isNavKeyPress()){
6728 this.validationTask.delay(this.validationDelay);
6732 * Validates the field value
6733 * @return {Boolean} True if the value is valid, else false
6735 validate : function(){
6736 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6737 if(this.disabled || this.validateValue(this.getRawValue())){
6738 this.clearInvalid();
6746 * Validates a value according to the field's validation rules and marks the field as invalid
6747 * if the validation fails
6748 * @param {Mixed} value The value to validate
6749 * @return {Boolean} True if the value is valid, else false
6751 validateValue : function(value){
6752 if(value.length < 1) { // if it's blank
6753 if(this.allowBlank){
6754 this.clearInvalid();
6757 this.markInvalid(this.blankText);
6761 if(value.length < this.minLength){
6762 this.markInvalid(String.format(this.minLengthText, this.minLength));
6765 if(value.length > this.maxLength){
6766 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6770 var vt = Roo.form.VTypes;
6771 if(!vt[this.vtype](value, this)){
6772 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6776 if(typeof this.validator == "function"){
6777 var msg = this.validator(value);
6779 this.markInvalid(msg);
6783 if(this.regex && !this.regex.test(value)){
6784 this.markInvalid(this.regexText);
6793 fireKey : function(e){
6794 //Roo.log('field ' + e.getKey());
6795 if(e.isNavKeyPress()){
6796 this.fireEvent("specialkey", this, e);
6799 focus : function (selectText){
6801 this.inputEl().focus();
6802 if(selectText === true){
6803 this.inputEl().dom.select();
6809 onFocus : function(){
6810 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6811 // this.el.addClass(this.focusClass);
6814 this.hasFocus = true;
6815 this.startValue = this.getValue();
6816 this.fireEvent("focus", this);
6820 beforeBlur : Roo.emptyFn,
6824 onBlur : function(){
6826 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6827 //this.el.removeClass(this.focusClass);
6829 this.hasFocus = false;
6830 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6833 var v = this.getValue();
6834 if(String(v) !== String(this.startValue)){
6835 this.fireEvent('change', this, v, this.startValue);
6837 this.fireEvent("blur", this);
6841 * Resets the current field value to the originally loaded value and clears any validation messages
6844 this.setValue(this.originalValue);
6845 this.clearInvalid();
6848 * Returns the name of the field
6849 * @return {Mixed} name The name field
6851 getName: function(){
6855 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6856 * @return {Mixed} value The field value
6858 getValue : function(){
6859 return this.inputEl().getValue();
6862 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6863 * @return {Mixed} value The field value
6865 getRawValue : function(){
6866 var v = this.inputEl().getValue();
6872 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6873 * @param {Mixed} value The value to set
6875 setRawValue : function(v){
6876 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6879 selectText : function(start, end){
6880 var v = this.getRawValue();
6882 start = start === undefined ? 0 : start;
6883 end = end === undefined ? v.length : end;
6884 var d = this.inputEl().dom;
6885 if(d.setSelectionRange){
6886 d.setSelectionRange(start, end);
6887 }else if(d.createTextRange){
6888 var range = d.createTextRange();
6889 range.moveStart("character", start);
6890 range.moveEnd("character", v.length-end);
6897 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6898 * @param {Mixed} value The value to set
6900 setValue : function(v){
6903 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6909 processValue : function(value){
6910 if(this.stripCharsRe){
6911 var newValue = value.replace(this.stripCharsRe, '');
6912 if(newValue !== value){
6913 this.setRawValue(newValue);
6920 preFocus : function(){
6922 if(this.selectOnFocus){
6923 this.inputEl().dom.select();
6926 filterKeys : function(e){
6928 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6931 var c = e.getCharCode(), cc = String.fromCharCode(c);
6932 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6935 if(!this.maskRe.test(cc)){
6940 * Clear any invalid styles/messages for this field
6942 clearInvalid : function(){
6944 if(!this.el || this.preventMark){ // not rendered
6947 this.el.removeClass(this.invalidClass);
6949 switch(this.msgTarget){
6951 this.el.dom.qtip = '';
6954 this.el.dom.title = '';
6958 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6963 this.errorIcon.dom.qtip = '';
6964 this.errorIcon.hide();
6965 this.un('resize', this.alignErrorIcon, this);
6969 var t = Roo.getDom(this.msgTarget);
6971 t.style.display = 'none';
6975 this.fireEvent('valid', this);
6978 * Mark this field as invalid
6979 * @param {String} msg The validation message
6981 markInvalid : function(msg){
6982 if(!this.el || this.preventMark){ // not rendered
6985 this.el.addClass(this.invalidClass);
6987 msg = msg || this.invalidText;
6988 switch(this.msgTarget){
6990 this.el.dom.qtip = msg;
6991 this.el.dom.qclass = 'x-form-invalid-tip';
6992 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6993 Roo.QuickTips.enable();
6997 this.el.dom.title = msg;
7001 var elp = this.el.findParent('.x-form-element', 5, true);
7002 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
7003 this.errorEl.setWidth(elp.getWidth(true)-20);
7005 this.errorEl.update(msg);
7006 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
7009 if(!this.errorIcon){
7010 var elp = this.el.findParent('.x-form-element', 5, true);
7011 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
7013 this.alignErrorIcon();
7014 this.errorIcon.dom.qtip = msg;
7015 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
7016 this.errorIcon.show();
7017 this.on('resize', this.alignErrorIcon, this);
7020 var t = Roo.getDom(this.msgTarget);
7022 t.style.display = this.msgDisplay;
7026 this.fireEvent('invalid', this, msg);
7029 SafariOnKeyDown : function(event)
7031 // this is a workaround for a password hang bug on chrome/ webkit.
7033 var isSelectAll = false;
7035 if(this.inputEl().dom.selectionEnd > 0){
7036 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
7038 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
7039 event.preventDefault();
7044 if(isSelectAll){ // backspace and delete key
7046 event.preventDefault();
7047 // this is very hacky as keydown always get's upper case.
7049 var cc = String.fromCharCode(event.getCharCode());
7050 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
7054 adjustWidth : function(tag, w){
7055 tag = tag.toLowerCase();
7056 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
7057 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
7061 if(tag == 'textarea'){
7064 }else if(Roo.isOpera){
7068 if(tag == 'textarea'){
7087 * @class Roo.bootstrap.TextArea
7088 * @extends Roo.bootstrap.Input
7089 * Bootstrap TextArea class
7090 * @cfg {Number} cols Specifies the visible width of a text area
7091 * @cfg {Number} rows Specifies the visible number of lines in a text area
7092 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
7093 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
7094 * @cfg {string} html text
7097 * Create a new TextArea
7098 * @param {Object} config The config object
7101 Roo.bootstrap.TextArea = function(config){
7102 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
7106 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
7116 getAutoCreate : function(){
7118 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
7129 value : this.value || '',
7130 html: this.html || '',
7131 cls : 'form-control',
7132 placeholder : this.placeholder || ''
7136 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
7137 input.maxLength = this.maxLength;
7141 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
7145 input.cols = this.cols;
7148 if (this.readOnly) {
7149 input.readonly = true;
7153 input.name = this.name;
7157 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
7161 ['xs','sm','md','lg'].map(function(size){
7162 if (settings[size]) {
7163 cfg.cls += ' col-' + size + '-' + settings[size];
7167 var inputblock = input;
7169 if (this.before || this.after) {
7172 cls : 'input-group',
7176 inputblock.cn.push({
7178 cls : 'input-group-addon',
7182 inputblock.cn.push(input);
7184 inputblock.cn.push({
7186 cls : 'input-group-addon',
7193 if (align ==='left' && this.fieldLabel.length) {
7194 Roo.log("left and has label");
7200 cls : 'control-label col-sm-' + this.labelWidth,
7201 html : this.fieldLabel
7205 cls : "col-sm-" + (12 - this.labelWidth),
7212 } else if ( this.fieldLabel.length) {
7218 //cls : 'input-group-addon',
7219 html : this.fieldLabel
7229 Roo.log(" no label && no align");
7239 if (this.disabled) {
7240 input.disabled=true;
7247 * return the real textarea element.
7249 inputEl: function ()
7251 return this.el.select('textarea.form-control',true).first();
7259 * trigger field - base class for combo..
7264 * @class Roo.bootstrap.TriggerField
7265 * @extends Roo.bootstrap.Input
7266 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
7267 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
7268 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
7269 * for which you can provide a custom implementation. For example:
7271 var trigger = new Roo.bootstrap.TriggerField();
7272 trigger.onTriggerClick = myTriggerFn;
7273 trigger.applyTo('my-field');
7276 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
7277 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
7278 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
7279 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
7281 * Create a new TriggerField.
7282 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
7283 * to the base TextField)
7285 Roo.bootstrap.TriggerField = function(config){
7286 this.mimicing = false;
7287 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
7290 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
7292 * @cfg {String} triggerClass A CSS class to apply to the trigger
7295 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
7299 /** @cfg {Boolean} grow @hide */
7300 /** @cfg {Number} growMin @hide */
7301 /** @cfg {Number} growMax @hide */
7307 autoSize: Roo.emptyFn,
7314 actionMode : 'wrap',
7318 getAutoCreate : function(){
7320 var parent = this.parent();
7322 var align = this.labelAlign || this.parentLabelAlign();
7327 cls: 'form-group' //input-group
7334 type : this.inputType,
7335 cls : 'form-control',
7336 autocomplete: 'off',
7337 placeholder : this.placeholder || ''
7341 input.name = this.name;
7344 input.cls += ' input-' + this.size;
7347 if (this.disabled) {
7348 input.disabled=true;
7351 var inputblock = input;
7353 if (this.before || this.after) {
7356 cls : 'input-group',
7360 inputblock.cn.push({
7362 cls : 'input-group-addon',
7366 inputblock.cn.push(input);
7368 inputblock.cn.push({
7370 cls : 'input-group-addon',
7383 cls: 'form-hidden-field'
7391 Roo.log('multiple');
7399 cls: 'form-hidden-field'
7403 cls: 'select2-choices',
7407 cls: 'select2-search-field',
7420 cls: 'select2-container input-group',
7425 cls: 'typeahead typeahead-long dropdown-menu',
7426 style: 'display:none'
7434 cls : 'input-group-addon btn dropdown-toggle',
7442 cls: 'combobox-clear',
7456 combobox.cls += ' select2-container-multi';
7459 if (align ==='left' && this.fieldLabel.length) {
7461 Roo.log("left and has label");
7467 cls : 'control-label col-sm-' + this.labelWidth,
7468 html : this.fieldLabel
7472 cls : "col-sm-" + (12 - this.labelWidth),
7479 } else if ( this.fieldLabel.length) {
7485 //cls : 'input-group-addon',
7486 html : this.fieldLabel
7496 Roo.log(" no label && no align");
7503 ['xs','sm','md','lg'].map(function(size){
7504 if (settings[size]) {
7505 cfg.cls += ' col-' + size + '-' + settings[size];
7516 onResize : function(w, h){
7517 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
7518 // if(typeof w == 'number'){
7519 // var x = w - this.trigger.getWidth();
7520 // this.inputEl().setWidth(this.adjustWidth('input', x));
7521 // this.trigger.setStyle('left', x+'px');
7526 adjustSize : Roo.BoxComponent.prototype.adjustSize,
7529 getResizeEl : function(){
7530 return this.inputEl();
7534 getPositionEl : function(){
7535 return this.inputEl();
7539 alignErrorIcon : function(){
7540 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
7544 initEvents : function(){
7546 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
7547 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
7549 this.trigger = this.el.select('span.dropdown-toggle',true).first();
7550 if(this.hideTrigger){
7551 this.trigger.setDisplayed(false);
7553 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
7557 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
7560 //this.trigger.addClassOnOver('x-form-trigger-over');
7561 //this.trigger.addClassOnClick('x-form-trigger-click');
7564 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
7569 initTrigger : function(){
7574 onDestroy : function(){
7576 this.trigger.removeAllListeners();
7577 // this.trigger.remove();
7580 // this.wrap.remove();
7582 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
7586 onFocus : function(){
7587 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
7590 this.wrap.addClass('x-trigger-wrap-focus');
7591 this.mimicing = true;
7592 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
7593 if(this.monitorTab){
7594 this.el.on("keydown", this.checkTab, this);
7601 checkTab : function(e){
7602 if(e.getKey() == e.TAB){
7608 onBlur : function(){
7613 mimicBlur : function(e, t){
7615 if(!this.wrap.contains(t) && this.validateBlur()){
7622 triggerBlur : function(){
7623 this.mimicing = false;
7624 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
7625 if(this.monitorTab){
7626 this.el.un("keydown", this.checkTab, this);
7628 //this.wrap.removeClass('x-trigger-wrap-focus');
7629 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
7633 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
7634 validateBlur : function(e, t){
7639 onDisable : function(){
7640 this.inputEl().dom.disabled = true;
7641 //Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
7643 // this.wrap.addClass('x-item-disabled');
7648 onEnable : function(){
7649 this.inputEl().dom.disabled = false;
7650 //Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
7652 // this.el.removeClass('x-item-disabled');
7657 onShow : function(){
7658 var ae = this.getActionEl();
7661 ae.dom.style.display = '';
7662 ae.dom.style.visibility = 'visible';
7668 onHide : function(){
7669 var ae = this.getActionEl();
7670 ae.dom.style.display = 'none';
7674 * The function that should handle the trigger's click event. This method does nothing by default until overridden
7675 * by an implementing function.
7677 * @param {EventObject} e
7679 onTriggerClick : Roo.emptyFn
7683 * Ext JS Library 1.1.1
7684 * Copyright(c) 2006-2007, Ext JS, LLC.
7686 * Originally Released Under LGPL - original licence link has changed is not relivant.
7689 * <script type="text/javascript">
7694 * @class Roo.data.SortTypes
7696 * Defines the default sorting (casting?) comparison functions used when sorting data.
7698 Roo.data.SortTypes = {
7700 * Default sort that does nothing
7701 * @param {Mixed} s The value being converted
7702 * @return {Mixed} The comparison value
7709 * The regular expression used to strip tags
7713 stripTagsRE : /<\/?[^>]+>/gi,
7716 * Strips all HTML tags to sort on text only
7717 * @param {Mixed} s The value being converted
7718 * @return {String} The comparison value
7720 asText : function(s){
7721 return String(s).replace(this.stripTagsRE, "");
7725 * Strips all HTML tags to sort on text only - Case insensitive
7726 * @param {Mixed} s The value being converted
7727 * @return {String} The comparison value
7729 asUCText : function(s){
7730 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7734 * Case insensitive string
7735 * @param {Mixed} s The value being converted
7736 * @return {String} The comparison value
7738 asUCString : function(s) {
7739 return String(s).toUpperCase();
7744 * @param {Mixed} s The value being converted
7745 * @return {Number} The comparison value
7747 asDate : function(s) {
7751 if(s instanceof Date){
7754 return Date.parse(String(s));
7759 * @param {Mixed} s The value being converted
7760 * @return {Float} The comparison value
7762 asFloat : function(s) {
7763 var val = parseFloat(String(s).replace(/,/g, ""));
7764 if(isNaN(val)) val = 0;
7770 * @param {Mixed} s The value being converted
7771 * @return {Number} The comparison value
7773 asInt : function(s) {
7774 var val = parseInt(String(s).replace(/,/g, ""));
7775 if(isNaN(val)) val = 0;
7780 * Ext JS Library 1.1.1
7781 * Copyright(c) 2006-2007, Ext JS, LLC.
7783 * Originally Released Under LGPL - original licence link has changed is not relivant.
7786 * <script type="text/javascript">
7790 * @class Roo.data.Record
7791 * Instances of this class encapsulate both record <em>definition</em> information, and record
7792 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7793 * to access Records cached in an {@link Roo.data.Store} object.<br>
7795 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7796 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7799 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7801 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7802 * {@link #create}. The parameters are the same.
7803 * @param {Array} data An associative Array of data values keyed by the field name.
7804 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7805 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7806 * not specified an integer id is generated.
7808 Roo.data.Record = function(data, id){
7809 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7814 * Generate a constructor for a specific record layout.
7815 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7816 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7817 * Each field definition object may contain the following properties: <ul>
7818 * <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,
7819 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7820 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7821 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7822 * is being used, then this is a string containing the javascript expression to reference the data relative to
7823 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7824 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7825 * this may be omitted.</p></li>
7826 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7827 * <ul><li>auto (Default, implies no conversion)</li>
7832 * <li>date</li></ul></p></li>
7833 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7834 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7835 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7836 * by the Reader into an object that will be stored in the Record. It is passed the
7837 * following parameters:<ul>
7838 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7840 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7842 * <br>usage:<br><pre><code>
7843 var TopicRecord = Roo.data.Record.create(
7844 {name: 'title', mapping: 'topic_title'},
7845 {name: 'author', mapping: 'username'},
7846 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7847 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7848 {name: 'lastPoster', mapping: 'user2'},
7849 {name: 'excerpt', mapping: 'post_text'}
7852 var myNewRecord = new TopicRecord({
7853 title: 'Do my job please',
7856 lastPost: new Date(),
7857 lastPoster: 'Animal',
7858 excerpt: 'No way dude!'
7860 myStore.add(myNewRecord);
7865 Roo.data.Record.create = function(o){
7867 f.superclass.constructor.apply(this, arguments);
7869 Roo.extend(f, Roo.data.Record);
7870 var p = f.prototype;
7871 p.fields = new Roo.util.MixedCollection(false, function(field){
7874 for(var i = 0, len = o.length; i < len; i++){
7875 p.fields.add(new Roo.data.Field(o[i]));
7877 f.getField = function(name){
7878 return p.fields.get(name);
7883 Roo.data.Record.AUTO_ID = 1000;
7884 Roo.data.Record.EDIT = 'edit';
7885 Roo.data.Record.REJECT = 'reject';
7886 Roo.data.Record.COMMIT = 'commit';
7888 Roo.data.Record.prototype = {
7890 * Readonly flag - true if this record has been modified.
7899 join : function(store){
7904 * Set the named field to the specified value.
7905 * @param {String} name The name of the field to set.
7906 * @param {Object} value The value to set the field to.
7908 set : function(name, value){
7909 if(this.data[name] == value){
7916 if(typeof this.modified[name] == 'undefined'){
7917 this.modified[name] = this.data[name];
7919 this.data[name] = value;
7920 if(!this.editing && this.store){
7921 this.store.afterEdit(this);
7926 * Get the value of the named field.
7927 * @param {String} name The name of the field to get the value of.
7928 * @return {Object} The value of the field.
7930 get : function(name){
7931 return this.data[name];
7935 beginEdit : function(){
7936 this.editing = true;
7941 cancelEdit : function(){
7942 this.editing = false;
7943 delete this.modified;
7947 endEdit : function(){
7948 this.editing = false;
7949 if(this.dirty && this.store){
7950 this.store.afterEdit(this);
7955 * Usually called by the {@link Roo.data.Store} which owns the Record.
7956 * Rejects all changes made to the Record since either creation, or the last commit operation.
7957 * Modified fields are reverted to their original values.
7959 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7960 * of reject operations.
7962 reject : function(){
7963 var m = this.modified;
7965 if(typeof m[n] != "function"){
7966 this.data[n] = m[n];
7970 delete this.modified;
7971 this.editing = false;
7973 this.store.afterReject(this);
7978 * Usually called by the {@link Roo.data.Store} which owns the Record.
7979 * Commits all changes made to the Record since either creation, or the last commit operation.
7981 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7982 * of commit operations.
7984 commit : function(){
7986 delete this.modified;
7987 this.editing = false;
7989 this.store.afterCommit(this);
7994 hasError : function(){
7995 return this.error != null;
7999 clearError : function(){
8004 * Creates a copy of this record.
8005 * @param {String} id (optional) A new record id if you don't want to use this record's id
8008 copy : function(newId) {
8009 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
8013 * Ext JS Library 1.1.1
8014 * Copyright(c) 2006-2007, Ext JS, LLC.
8016 * Originally Released Under LGPL - original licence link has changed is not relivant.
8019 * <script type="text/javascript">
8025 * @class Roo.data.Store
8026 * @extends Roo.util.Observable
8027 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
8028 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
8030 * 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
8031 * has no knowledge of the format of the data returned by the Proxy.<br>
8033 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
8034 * instances from the data object. These records are cached and made available through accessor functions.
8036 * Creates a new Store.
8037 * @param {Object} config A config object containing the objects needed for the Store to access data,
8038 * and read the data into Records.
8040 Roo.data.Store = function(config){
8041 this.data = new Roo.util.MixedCollection(false);
8042 this.data.getKey = function(o){
8045 this.baseParams = {};
8052 "multisort" : "_multisort"
8055 if(config && config.data){
8056 this.inlineData = config.data;
8060 Roo.apply(this, config);
8062 if(this.reader){ // reader passed
8063 this.reader = Roo.factory(this.reader, Roo.data);
8064 this.reader.xmodule = this.xmodule || false;
8065 if(!this.recordType){
8066 this.recordType = this.reader.recordType;
8068 if(this.reader.onMetaChange){
8069 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
8073 if(this.recordType){
8074 this.fields = this.recordType.prototype.fields;
8080 * @event datachanged
8081 * Fires when the data cache has changed, and a widget which is using this Store
8082 * as a Record cache should refresh its view.
8083 * @param {Store} this
8088 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
8089 * @param {Store} this
8090 * @param {Object} meta The JSON metadata
8095 * Fires when Records have been added to the Store
8096 * @param {Store} this
8097 * @param {Roo.data.Record[]} records The array of Records added
8098 * @param {Number} index The index at which the record(s) were added
8103 * Fires when a Record has been removed from the Store
8104 * @param {Store} this
8105 * @param {Roo.data.Record} record The Record that was removed
8106 * @param {Number} index The index at which the record was removed
8111 * Fires when a Record has been updated
8112 * @param {Store} this
8113 * @param {Roo.data.Record} record The Record that was updated
8114 * @param {String} operation The update operation being performed. Value may be one of:
8116 Roo.data.Record.EDIT
8117 Roo.data.Record.REJECT
8118 Roo.data.Record.COMMIT
8124 * Fires when the data cache has been cleared.
8125 * @param {Store} this
8130 * Fires before a request is made for a new data object. If the beforeload handler returns false
8131 * the load action will be canceled.
8132 * @param {Store} this
8133 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8137 * @event beforeloadadd
8138 * Fires after a new set of Records has been loaded.
8139 * @param {Store} this
8140 * @param {Roo.data.Record[]} records The Records that were loaded
8141 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8143 beforeloadadd : true,
8146 * Fires after a new set of Records has been loaded, before they are added to the store.
8147 * @param {Store} this
8148 * @param {Roo.data.Record[]} records The Records that were loaded
8149 * @param {Object} options The loading options that were specified (see {@link #load} for details)
8150 * @params {Object} return from reader
8154 * @event loadexception
8155 * Fires if an exception occurs in the Proxy during loading.
8156 * Called with the signature of the Proxy's "loadexception" event.
8157 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
8160 * @param {Object} return from JsonData.reader() - success, totalRecords, records
8161 * @param {Object} load options
8162 * @param {Object} jsonData from your request (normally this contains the Exception)
8164 loadexception : true
8168 this.proxy = Roo.factory(this.proxy, Roo.data);
8169 this.proxy.xmodule = this.xmodule || false;
8170 this.relayEvents(this.proxy, ["loadexception"]);
8172 this.sortToggle = {};
8173 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
8175 Roo.data.Store.superclass.constructor.call(this);
8177 if(this.inlineData){
8178 this.loadData(this.inlineData);
8179 delete this.inlineData;
8183 Roo.extend(Roo.data.Store, Roo.util.Observable, {
8185 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
8186 * without a remote query - used by combo/forms at present.
8190 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
8193 * @cfg {Array} data Inline data to be loaded when the store is initialized.
8196 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
8197 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
8200 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
8201 * on any HTTP request
8204 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
8207 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
8211 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
8212 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
8217 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
8218 * loaded or when a record is removed. (defaults to false).
8220 pruneModifiedRecords : false,
8226 * Add Records to the Store and fires the add event.
8227 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8229 add : function(records){
8230 records = [].concat(records);
8231 for(var i = 0, len = records.length; i < len; i++){
8232 records[i].join(this);
8234 var index = this.data.length;
8235 this.data.addAll(records);
8236 this.fireEvent("add", this, records, index);
8240 * Remove a Record from the Store and fires the remove event.
8241 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
8243 remove : function(record){
8244 var index = this.data.indexOf(record);
8245 this.data.removeAt(index);
8246 if(this.pruneModifiedRecords){
8247 this.modified.remove(record);
8249 this.fireEvent("remove", this, record, index);
8253 * Remove all Records from the Store and fires the clear event.
8255 removeAll : function(){
8257 if(this.pruneModifiedRecords){
8260 this.fireEvent("clear", this);
8264 * Inserts Records to the Store at the given index and fires the add event.
8265 * @param {Number} index The start index at which to insert the passed Records.
8266 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
8268 insert : function(index, records){
8269 records = [].concat(records);
8270 for(var i = 0, len = records.length; i < len; i++){
8271 this.data.insert(index, records[i]);
8272 records[i].join(this);
8274 this.fireEvent("add", this, records, index);
8278 * Get the index within the cache of the passed Record.
8279 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
8280 * @return {Number} The index of the passed Record. Returns -1 if not found.
8282 indexOf : function(record){
8283 return this.data.indexOf(record);
8287 * Get the index within the cache of the Record with the passed id.
8288 * @param {String} id The id of the Record to find.
8289 * @return {Number} The index of the Record. Returns -1 if not found.
8291 indexOfId : function(id){
8292 return this.data.indexOfKey(id);
8296 * Get the Record with the specified id.
8297 * @param {String} id The id of the Record to find.
8298 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
8300 getById : function(id){
8301 return this.data.key(id);
8305 * Get the Record at the specified index.
8306 * @param {Number} index The index of the Record to find.
8307 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
8309 getAt : function(index){
8310 return this.data.itemAt(index);
8314 * Returns a range of Records between specified indices.
8315 * @param {Number} startIndex (optional) The starting index (defaults to 0)
8316 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
8317 * @return {Roo.data.Record[]} An array of Records
8319 getRange : function(start, end){
8320 return this.data.getRange(start, end);
8324 storeOptions : function(o){
8325 o = Roo.apply({}, o);
8328 this.lastOptions = o;
8332 * Loads the Record cache from the configured Proxy using the configured Reader.
8334 * If using remote paging, then the first load call must specify the <em>start</em>
8335 * and <em>limit</em> properties in the options.params property to establish the initial
8336 * position within the dataset, and the number of Records to cache on each read from the Proxy.
8338 * <strong>It is important to note that for remote data sources, loading is asynchronous,
8339 * and this call will return before the new data has been loaded. Perform any post-processing
8340 * in a callback function, or in a "load" event handler.</strong>
8342 * @param {Object} options An object containing properties which control loading options:<ul>
8343 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
8344 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
8345 * passed the following arguments:<ul>
8346 * <li>r : Roo.data.Record[]</li>
8347 * <li>options: Options object from the load call</li>
8348 * <li>success: Boolean success indicator</li></ul></li>
8349 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
8350 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
8353 load : function(options){
8354 options = options || {};
8355 if(this.fireEvent("beforeload", this, options) !== false){
8356 this.storeOptions(options);
8357 var p = Roo.apply(options.params || {}, this.baseParams);
8358 // if meta was not loaded from remote source.. try requesting it.
8359 if (!this.reader.metaFromRemote) {
8362 if(this.sortInfo && this.remoteSort){
8363 var pn = this.paramNames;
8364 p[pn["sort"]] = this.sortInfo.field;
8365 p[pn["dir"]] = this.sortInfo.direction;
8367 if (this.multiSort) {
8368 var pn = this.paramNames;
8369 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
8372 this.proxy.load(p, this.reader, this.loadRecords, this, options);
8377 * Reloads the Record cache from the configured Proxy using the configured Reader and
8378 * the options from the last load operation performed.
8379 * @param {Object} options (optional) An object containing properties which may override the options
8380 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
8381 * the most recently used options are reused).
8383 reload : function(options){
8384 this.load(Roo.applyIf(options||{}, this.lastOptions));
8388 // Called as a callback by the Reader during a load operation.
8389 loadRecords : function(o, options, success){
8390 if(!o || success === false){
8391 if(success !== false){
8392 this.fireEvent("load", this, [], options, o);
8394 if(options.callback){
8395 options.callback.call(options.scope || this, [], options, false);
8399 // if data returned failure - throw an exception.
8400 if (o.success === false) {
8401 // show a message if no listener is registered.
8402 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
8403 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
8405 // loadmask wil be hooked into this..
8406 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
8409 var r = o.records, t = o.totalRecords || r.length;
8411 this.fireEvent("beforeloadadd", this, r, options, o);
8413 if(!options || options.add !== true){
8414 if(this.pruneModifiedRecords){
8417 for(var i = 0, len = r.length; i < len; i++){
8421 this.data = this.snapshot;
8422 delete this.snapshot;
8425 this.data.addAll(r);
8426 this.totalLength = t;
8428 this.fireEvent("datachanged", this);
8430 this.totalLength = Math.max(t, this.data.length+r.length);
8433 this.fireEvent("load", this, r, options, o);
8434 if(options.callback){
8435 options.callback.call(options.scope || this, r, options, true);
8441 * Loads data from a passed data block. A Reader which understands the format of the data
8442 * must have been configured in the constructor.
8443 * @param {Object} data The data block from which to read the Records. The format of the data expected
8444 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
8445 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
8447 loadData : function(o, append){
8448 var r = this.reader.readRecords(o);
8449 this.loadRecords(r, {add: append}, true);
8453 * Gets the number of cached records.
8455 * <em>If using paging, this may not be the total size of the dataset. If the data object
8456 * used by the Reader contains the dataset size, then the getTotalCount() function returns
8457 * the data set size</em>
8459 getCount : function(){
8460 return this.data.length || 0;
8464 * Gets the total number of records in the dataset as returned by the server.
8466 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
8467 * the dataset size</em>
8469 getTotalCount : function(){
8470 return this.totalLength || 0;
8474 * Returns the sort state of the Store as an object with two properties:
8476 field {String} The name of the field by which the Records are sorted
8477 direction {String} The sort order, "ASC" or "DESC"
8480 getSortState : function(){
8481 return this.sortInfo;
8485 applySort : function(){
8486 if(this.sortInfo && !this.remoteSort){
8487 var s = this.sortInfo, f = s.field;
8488 var st = this.fields.get(f).sortType;
8489 var fn = function(r1, r2){
8490 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
8491 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
8493 this.data.sort(s.direction, fn);
8494 if(this.snapshot && this.snapshot != this.data){
8495 this.snapshot.sort(s.direction, fn);
8501 * Sets the default sort column and order to be used by the next load operation.
8502 * @param {String} fieldName The name of the field to sort by.
8503 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8505 setDefaultSort : function(field, dir){
8506 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
8511 * If remote sorting is used, the sort is performed on the server, and the cache is
8512 * reloaded. If local sorting is used, the cache is sorted internally.
8513 * @param {String} fieldName The name of the field to sort by.
8514 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
8516 sort : function(fieldName, dir){
8517 var f = this.fields.get(fieldName);
8519 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
8521 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
8522 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
8527 this.sortToggle[f.name] = dir;
8528 this.sortInfo = {field: f.name, direction: dir};
8529 if(!this.remoteSort){
8531 this.fireEvent("datachanged", this);
8533 this.load(this.lastOptions);
8538 * Calls the specified function for each of the Records in the cache.
8539 * @param {Function} fn The function to call. The Record is passed as the first parameter.
8540 * Returning <em>false</em> aborts and exits the iteration.
8541 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
8543 each : function(fn, scope){
8544 this.data.each(fn, scope);
8548 * Gets all records modified since the last commit. Modified records are persisted across load operations
8549 * (e.g., during paging).
8550 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
8552 getModifiedRecords : function(){
8553 return this.modified;
8557 createFilterFn : function(property, value, anyMatch){
8558 if(!value.exec){ // not a regex
8559 value = String(value);
8560 if(value.length == 0){
8563 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
8566 return value.test(r.data[property]);
8571 * Sums the value of <i>property</i> for each record between start and end and returns the result.
8572 * @param {String} property A field on your records
8573 * @param {Number} start The record index to start at (defaults to 0)
8574 * @param {Number} end The last record index to include (defaults to length - 1)
8575 * @return {Number} The sum
8577 sum : function(property, start, end){
8578 var rs = this.data.items, v = 0;
8580 end = (end || end === 0) ? end : rs.length-1;
8582 for(var i = start; i <= end; i++){
8583 v += (rs[i].data[property] || 0);
8589 * Filter the records by a specified property.
8590 * @param {String} field A field on your records
8591 * @param {String/RegExp} value Either a string that the field
8592 * should start with or a RegExp to test against the field
8593 * @param {Boolean} anyMatch True to match any part not just the beginning
8595 filter : function(property, value, anyMatch){
8596 var fn = this.createFilterFn(property, value, anyMatch);
8597 return fn ? this.filterBy(fn) : this.clearFilter();
8601 * Filter by a function. The specified function will be called with each
8602 * record in this data source. If the function returns true the record is included,
8603 * otherwise it is filtered.
8604 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8605 * @param {Object} scope (optional) The scope of the function (defaults to this)
8607 filterBy : function(fn, scope){
8608 this.snapshot = this.snapshot || this.data;
8609 this.data = this.queryBy(fn, scope||this);
8610 this.fireEvent("datachanged", this);
8614 * Query the records by a specified property.
8615 * @param {String} field A field on your records
8616 * @param {String/RegExp} value Either a string that the field
8617 * should start with or a RegExp to test against the field
8618 * @param {Boolean} anyMatch True to match any part not just the beginning
8619 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8621 query : function(property, value, anyMatch){
8622 var fn = this.createFilterFn(property, value, anyMatch);
8623 return fn ? this.queryBy(fn) : this.data.clone();
8627 * Query by a function. The specified function will be called with each
8628 * record in this data source. If the function returns true the record is included
8630 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
8631 * @param {Object} scope (optional) The scope of the function (defaults to this)
8632 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
8634 queryBy : function(fn, scope){
8635 var data = this.snapshot || this.data;
8636 return data.filterBy(fn, scope||this);
8640 * Collects unique values for a particular dataIndex from this store.
8641 * @param {String} dataIndex The property to collect
8642 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
8643 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
8644 * @return {Array} An array of the unique values
8646 collect : function(dataIndex, allowNull, bypassFilter){
8647 var d = (bypassFilter === true && this.snapshot) ?
8648 this.snapshot.items : this.data.items;
8649 var v, sv, r = [], l = {};
8650 for(var i = 0, len = d.length; i < len; i++){
8651 v = d[i].data[dataIndex];
8653 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
8662 * Revert to a view of the Record cache with no filtering applied.
8663 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
8665 clearFilter : function(suppressEvent){
8666 if(this.snapshot && this.snapshot != this.data){
8667 this.data = this.snapshot;
8668 delete this.snapshot;
8669 if(suppressEvent !== true){
8670 this.fireEvent("datachanged", this);
8676 afterEdit : function(record){
8677 if(this.modified.indexOf(record) == -1){
8678 this.modified.push(record);
8680 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
8684 afterReject : function(record){
8685 this.modified.remove(record);
8686 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
8690 afterCommit : function(record){
8691 this.modified.remove(record);
8692 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
8696 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
8697 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
8699 commitChanges : function(){
8700 var m = this.modified.slice(0);
8702 for(var i = 0, len = m.length; i < len; i++){
8708 * Cancel outstanding changes on all changed records.
8710 rejectChanges : function(){
8711 var m = this.modified.slice(0);
8713 for(var i = 0, len = m.length; i < len; i++){
8718 onMetaChange : function(meta, rtype, o){
8719 this.recordType = rtype;
8720 this.fields = rtype.prototype.fields;
8721 delete this.snapshot;
8722 this.sortInfo = meta.sortInfo || this.sortInfo;
8724 this.fireEvent('metachange', this, this.reader.meta);
8727 moveIndex : function(data, type)
8729 var index = this.indexOf(data);
8731 var newIndex = index + type;
8735 this.insert(newIndex, data);
8740 * Ext JS Library 1.1.1
8741 * Copyright(c) 2006-2007, Ext JS, LLC.
8743 * Originally Released Under LGPL - original licence link has changed is not relivant.
8746 * <script type="text/javascript">
8750 * @class Roo.data.SimpleStore
8751 * @extends Roo.data.Store
8752 * Small helper class to make creating Stores from Array data easier.
8753 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8754 * @cfg {Array} fields An array of field definition objects, or field name strings.
8755 * @cfg {Array} data The multi-dimensional array of data
8757 * @param {Object} config
8759 Roo.data.SimpleStore = function(config){
8760 Roo.data.SimpleStore.superclass.constructor.call(this, {
8762 reader: new Roo.data.ArrayReader({
8765 Roo.data.Record.create(config.fields)
8767 proxy : new Roo.data.MemoryProxy(config.data)
8771 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8773 * Ext JS Library 1.1.1
8774 * Copyright(c) 2006-2007, Ext JS, LLC.
8776 * Originally Released Under LGPL - original licence link has changed is not relivant.
8779 * <script type="text/javascript">
8784 * @extends Roo.data.Store
8785 * @class Roo.data.JsonStore
8786 * Small helper class to make creating Stores for JSON data easier. <br/>
8788 var store = new Roo.data.JsonStore({
8789 url: 'get-images.php',
8791 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8794 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8795 * JsonReader and HttpProxy (unless inline data is provided).</b>
8796 * @cfg {Array} fields An array of field definition objects, or field name strings.
8798 * @param {Object} config
8800 Roo.data.JsonStore = function(c){
8801 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8802 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8803 reader: new Roo.data.JsonReader(c, c.fields)
8806 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8808 * Ext JS Library 1.1.1
8809 * Copyright(c) 2006-2007, Ext JS, LLC.
8811 * Originally Released Under LGPL - original licence link has changed is not relivant.
8814 * <script type="text/javascript">
8818 Roo.data.Field = function(config){
8819 if(typeof config == "string"){
8820 config = {name: config};
8822 Roo.apply(this, config);
8828 var st = Roo.data.SortTypes;
8829 // named sortTypes are supported, here we look them up
8830 if(typeof this.sortType == "string"){
8831 this.sortType = st[this.sortType];
8834 // set default sortType for strings and dates
8838 this.sortType = st.asUCString;
8841 this.sortType = st.asDate;
8844 this.sortType = st.none;
8849 var stripRe = /[\$,%]/g;
8851 // prebuilt conversion function for this field, instead of
8852 // switching every time we're reading a value
8854 var cv, dateFormat = this.dateFormat;
8859 cv = function(v){ return v; };
8862 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8866 return v !== undefined && v !== null && v !== '' ?
8867 parseInt(String(v).replace(stripRe, ""), 10) : '';
8872 return v !== undefined && v !== null && v !== '' ?
8873 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8878 cv = function(v){ return v === true || v === "true" || v == 1; };
8885 if(v instanceof Date){
8889 if(dateFormat == "timestamp"){
8890 return new Date(v*1000);
8892 return Date.parseDate(v, dateFormat);
8894 var parsed = Date.parse(v);
8895 return parsed ? new Date(parsed) : null;
8904 Roo.data.Field.prototype = {
8912 * Ext JS Library 1.1.1
8913 * Copyright(c) 2006-2007, Ext JS, LLC.
8915 * Originally Released Under LGPL - original licence link has changed is not relivant.
8918 * <script type="text/javascript">
8921 // Base class for reading structured data from a data source. This class is intended to be
8922 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8925 * @class Roo.data.DataReader
8926 * Base class for reading structured data from a data source. This class is intended to be
8927 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8930 Roo.data.DataReader = function(meta, recordType){
8934 this.recordType = recordType instanceof Array ?
8935 Roo.data.Record.create(recordType) : recordType;
8938 Roo.data.DataReader.prototype = {
8940 * Create an empty record
8941 * @param {Object} data (optional) - overlay some values
8942 * @return {Roo.data.Record} record created.
8944 newRow : function(d) {
8946 this.recordType.prototype.fields.each(function(c) {
8948 case 'int' : da[c.name] = 0; break;
8949 case 'date' : da[c.name] = new Date(); break;
8950 case 'float' : da[c.name] = 0.0; break;
8951 case 'boolean' : da[c.name] = false; break;
8952 default : da[c.name] = ""; break;
8956 return new this.recordType(Roo.apply(da, d));
8961 * Ext JS Library 1.1.1
8962 * Copyright(c) 2006-2007, Ext JS, LLC.
8964 * Originally Released Under LGPL - original licence link has changed is not relivant.
8967 * <script type="text/javascript">
8971 * @class Roo.data.DataProxy
8972 * @extends Roo.data.Observable
8973 * This class is an abstract base class for implementations which provide retrieval of
8974 * unformatted data objects.<br>
8976 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8977 * (of the appropriate type which knows how to parse the data object) to provide a block of
8978 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8980 * Custom implementations must implement the load method as described in
8981 * {@link Roo.data.HttpProxy#load}.
8983 Roo.data.DataProxy = function(){
8987 * Fires before a network request is made to retrieve a data object.
8988 * @param {Object} This DataProxy object.
8989 * @param {Object} params The params parameter to the load function.
8994 * Fires before the load method's callback is called.
8995 * @param {Object} This DataProxy object.
8996 * @param {Object} o The data object.
8997 * @param {Object} arg The callback argument object passed to the load function.
9001 * @event loadexception
9002 * Fires if an Exception occurs during data retrieval.
9003 * @param {Object} This DataProxy object.
9004 * @param {Object} o The data object.
9005 * @param {Object} arg The callback argument object passed to the load function.
9006 * @param {Object} e The Exception.
9008 loadexception : true
9010 Roo.data.DataProxy.superclass.constructor.call(this);
9013 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
9016 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
9020 * Ext JS Library 1.1.1
9021 * Copyright(c) 2006-2007, Ext JS, LLC.
9023 * Originally Released Under LGPL - original licence link has changed is not relivant.
9026 * <script type="text/javascript">
9029 * @class Roo.data.MemoryProxy
9030 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
9031 * to the Reader when its load method is called.
9033 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
9035 Roo.data.MemoryProxy = function(data){
9039 Roo.data.MemoryProxy.superclass.constructor.call(this);
9043 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
9045 * Load data from the requested source (in this case an in-memory
9046 * data object passed to the constructor), read the data object into
9047 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9048 * process that block using the passed callback.
9049 * @param {Object} params This parameter is not used by the MemoryProxy class.
9050 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9051 * object into a block of Roo.data.Records.
9052 * @param {Function} callback The function into which to pass the block of Roo.data.records.
9053 * The function must be passed <ul>
9054 * <li>The Record block object</li>
9055 * <li>The "arg" argument from the load function</li>
9056 * <li>A boolean success indicator</li>
9058 * @param {Object} scope The scope in which to call the callback
9059 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9061 load : function(params, reader, callback, scope, arg){
9062 params = params || {};
9065 result = reader.readRecords(this.data);
9067 this.fireEvent("loadexception", this, arg, null, e);
9068 callback.call(scope, null, arg, false);
9071 callback.call(scope, result, arg, true);
9075 update : function(params, records){
9080 * Ext JS Library 1.1.1
9081 * Copyright(c) 2006-2007, Ext JS, LLC.
9083 * Originally Released Under LGPL - original licence link has changed is not relivant.
9086 * <script type="text/javascript">
9089 * @class Roo.data.HttpProxy
9090 * @extends Roo.data.DataProxy
9091 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
9092 * configured to reference a certain URL.<br><br>
9094 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
9095 * from which the running page was served.<br><br>
9097 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
9099 * Be aware that to enable the browser to parse an XML document, the server must set
9100 * the Content-Type header in the HTTP response to "text/xml".
9102 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
9103 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
9104 * will be used to make the request.
9106 Roo.data.HttpProxy = function(conn){
9107 Roo.data.HttpProxy.superclass.constructor.call(this);
9108 // is conn a conn config or a real conn?
9110 this.useAjax = !conn || !conn.events;
9114 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
9115 // thse are take from connection...
9118 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
9121 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
9122 * extra parameters to each request made by this object. (defaults to undefined)
9125 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
9126 * to each request made by this object. (defaults to undefined)
9129 * @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)
9132 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
9135 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
9141 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
9145 * Return the {@link Roo.data.Connection} object being used by this Proxy.
9146 * @return {Connection} The Connection object. This object may be used to subscribe to events on
9147 * a finer-grained basis than the DataProxy events.
9149 getConnection : function(){
9150 return this.useAjax ? Roo.Ajax : this.conn;
9154 * Load data from the configured {@link Roo.data.Connection}, read the data object into
9155 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
9156 * process that block using the passed callback.
9157 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9158 * for the request to the remote server.
9159 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9160 * object into a block of Roo.data.Records.
9161 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9162 * The function must be passed <ul>
9163 * <li>The Record block object</li>
9164 * <li>The "arg" argument from the load function</li>
9165 * <li>A boolean success indicator</li>
9167 * @param {Object} scope The scope in which to call the callback
9168 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9170 load : function(params, reader, callback, scope, arg){
9171 if(this.fireEvent("beforeload", this, params) !== false){
9173 params : params || {},
9175 callback : callback,
9180 callback : this.loadResponse,
9184 Roo.applyIf(o, this.conn);
9185 if(this.activeRequest){
9186 Roo.Ajax.abort(this.activeRequest);
9188 this.activeRequest = Roo.Ajax.request(o);
9190 this.conn.request(o);
9193 callback.call(scope||this, null, arg, false);
9198 loadResponse : function(o, success, response){
9199 delete this.activeRequest;
9201 this.fireEvent("loadexception", this, o, response);
9202 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9207 result = o.reader.read(response);
9209 this.fireEvent("loadexception", this, o, response, e);
9210 o.request.callback.call(o.request.scope, null, o.request.arg, false);
9214 this.fireEvent("load", this, o, o.request.arg);
9215 o.request.callback.call(o.request.scope, result, o.request.arg, true);
9219 update : function(dataSet){
9224 updateResponse : function(dataSet){
9229 * Ext JS Library 1.1.1
9230 * Copyright(c) 2006-2007, Ext JS, LLC.
9232 * Originally Released Under LGPL - original licence link has changed is not relivant.
9235 * <script type="text/javascript">
9239 * @class Roo.data.ScriptTagProxy
9240 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
9241 * other than the originating domain of the running page.<br><br>
9243 * <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
9244 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
9246 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
9247 * source code that is used as the source inside a <script> tag.<br><br>
9249 * In order for the browser to process the returned data, the server must wrap the data object
9250 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
9251 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
9252 * depending on whether the callback name was passed:
9255 boolean scriptTag = false;
9256 String cb = request.getParameter("callback");
9259 response.setContentType("text/javascript");
9261 response.setContentType("application/x-json");
9263 Writer out = response.getWriter();
9265 out.write(cb + "(");
9267 out.print(dataBlock.toJsonString());
9274 * @param {Object} config A configuration object.
9276 Roo.data.ScriptTagProxy = function(config){
9277 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
9278 Roo.apply(this, config);
9279 this.head = document.getElementsByTagName("head")[0];
9282 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
9284 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
9286 * @cfg {String} url The URL from which to request the data object.
9289 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
9293 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
9294 * the server the name of the callback function set up by the load call to process the returned data object.
9295 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
9296 * javascript output which calls this named function passing the data object as its only parameter.
9298 callbackParam : "callback",
9300 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
9301 * name to the request.
9306 * Load data from the configured URL, read the data object into
9307 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
9308 * process that block using the passed callback.
9309 * @param {Object} params An object containing properties which are to be used as HTTP parameters
9310 * for the request to the remote server.
9311 * @param {Roo.data.DataReader} reader The Reader object which converts the data
9312 * object into a block of Roo.data.Records.
9313 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
9314 * The function must be passed <ul>
9315 * <li>The Record block object</li>
9316 * <li>The "arg" argument from the load function</li>
9317 * <li>A boolean success indicator</li>
9319 * @param {Object} scope The scope in which to call the callback
9320 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
9322 load : function(params, reader, callback, scope, arg){
9323 if(this.fireEvent("beforeload", this, params) !== false){
9325 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
9328 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
9330 url += "&_dc=" + (new Date().getTime());
9332 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
9335 cb : "stcCallback"+transId,
9336 scriptId : "stcScript"+transId,
9340 callback : callback,
9346 window[trans.cb] = function(o){
9347 conn.handleResponse(o, trans);
9350 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
9352 if(this.autoAbort !== false){
9356 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
9358 var script = document.createElement("script");
9359 script.setAttribute("src", url);
9360 script.setAttribute("type", "text/javascript");
9361 script.setAttribute("id", trans.scriptId);
9362 this.head.appendChild(script);
9366 callback.call(scope||this, null, arg, false);
9371 isLoading : function(){
9372 return this.trans ? true : false;
9376 * Abort the current server request.
9379 if(this.isLoading()){
9380 this.destroyTrans(this.trans);
9385 destroyTrans : function(trans, isLoaded){
9386 this.head.removeChild(document.getElementById(trans.scriptId));
9387 clearTimeout(trans.timeoutId);
9389 window[trans.cb] = undefined;
9391 delete window[trans.cb];
9394 // if hasn't been loaded, wait for load to remove it to prevent script error
9395 window[trans.cb] = function(){
9396 window[trans.cb] = undefined;
9398 delete window[trans.cb];
9405 handleResponse : function(o, trans){
9407 this.destroyTrans(trans, true);
9410 result = trans.reader.readRecords(o);
9412 this.fireEvent("loadexception", this, o, trans.arg, e);
9413 trans.callback.call(trans.scope||window, null, trans.arg, false);
9416 this.fireEvent("load", this, o, trans.arg);
9417 trans.callback.call(trans.scope||window, result, trans.arg, true);
9421 handleFailure : function(trans){
9423 this.destroyTrans(trans, false);
9424 this.fireEvent("loadexception", this, null, trans.arg);
9425 trans.callback.call(trans.scope||window, null, trans.arg, false);
9429 * Ext JS Library 1.1.1
9430 * Copyright(c) 2006-2007, Ext JS, LLC.
9432 * Originally Released Under LGPL - original licence link has changed is not relivant.
9435 * <script type="text/javascript">
9439 * @class Roo.data.JsonReader
9440 * @extends Roo.data.DataReader
9441 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
9442 * based on mappings in a provided Roo.data.Record constructor.
9444 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
9445 * in the reply previously.
9450 var RecordDef = Roo.data.Record.create([
9451 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
9452 {name: 'occupation'} // This field will use "occupation" as the mapping.
9454 var myReader = new Roo.data.JsonReader({
9455 totalProperty: "results", // The property which contains the total dataset size (optional)
9456 root: "rows", // The property which contains an Array of row objects
9457 id: "id" // The property within each row object that provides an ID for the record (optional)
9461 * This would consume a JSON file like this:
9463 { 'results': 2, 'rows': [
9464 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
9465 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
9468 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
9469 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
9470 * paged from the remote server.
9471 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
9472 * @cfg {String} root name of the property which contains the Array of row objects.
9473 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
9475 * Create a new JsonReader
9476 * @param {Object} meta Metadata configuration options
9477 * @param {Object} recordType Either an Array of field definition objects,
9478 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
9480 Roo.data.JsonReader = function(meta, recordType){
9483 // set some defaults:
9485 totalProperty: 'total',
9486 successProperty : 'success',
9491 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
9493 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
9496 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
9497 * Used by Store query builder to append _requestMeta to params.
9500 metaFromRemote : false,
9502 * This method is only used by a DataProxy which has retrieved data from a remote server.
9503 * @param {Object} response The XHR object which contains the JSON data in its responseText.
9504 * @return {Object} data A data block which is used by an Roo.data.Store object as
9505 * a cache of Roo.data.Records.
9507 read : function(response){
9508 var json = response.responseText;
9510 var o = /* eval:var:o */ eval("("+json+")");
9512 throw {message: "JsonReader.read: Json object not found"};
9518 this.metaFromRemote = true;
9519 this.meta = o.metaData;
9520 this.recordType = Roo.data.Record.create(o.metaData.fields);
9521 this.onMetaChange(this.meta, this.recordType, o);
9523 return this.readRecords(o);
9526 // private function a store will implement
9527 onMetaChange : function(meta, recordType, o){
9534 simpleAccess: function(obj, subsc) {
9541 getJsonAccessor: function(){
9543 return function(expr) {
9545 return(re.test(expr))
9546 ? new Function("obj", "return obj." + expr)
9556 * Create a data block containing Roo.data.Records from an XML document.
9557 * @param {Object} o An object which contains an Array of row objects in the property specified
9558 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
9559 * which contains the total size of the dataset.
9560 * @return {Object} data A data block which is used by an Roo.data.Store object as
9561 * a cache of Roo.data.Records.
9563 readRecords : function(o){
9565 * After any data loads, the raw JSON data is available for further custom processing.
9569 var s = this.meta, Record = this.recordType,
9570 f = Record.prototype.fields, fi = f.items, fl = f.length;
9572 // Generate extraction functions for the totalProperty, the root, the id, and for each field
9574 if(s.totalProperty) {
9575 this.getTotal = this.getJsonAccessor(s.totalProperty);
9577 if(s.successProperty) {
9578 this.getSuccess = this.getJsonAccessor(s.successProperty);
9580 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
9582 var g = this.getJsonAccessor(s.id);
9583 this.getId = function(rec) {
9585 return (r === undefined || r === "") ? null : r;
9588 this.getId = function(){return null;};
9591 for(var jj = 0; jj < fl; jj++){
9593 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
9594 this.ef[jj] = this.getJsonAccessor(map);
9598 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
9599 if(s.totalProperty){
9600 var vt = parseInt(this.getTotal(o), 10);
9605 if(s.successProperty){
9606 var vs = this.getSuccess(o);
9607 if(vs === false || vs === 'false'){
9612 for(var i = 0; i < c; i++){
9615 var id = this.getId(n);
9616 for(var j = 0; j < fl; j++){
9618 var v = this.ef[j](n);
9620 Roo.log('missing convert for ' + f.name);
9624 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
9626 var record = new Record(values, id);
9628 records[i] = record;
9634 totalRecords : totalRecords
9639 * Ext JS Library 1.1.1
9640 * Copyright(c) 2006-2007, Ext JS, LLC.
9642 * Originally Released Under LGPL - original licence link has changed is not relivant.
9645 * <script type="text/javascript">
9649 * @class Roo.data.ArrayReader
9650 * @extends Roo.data.DataReader
9651 * Data reader class to create an Array of Roo.data.Record objects from an Array.
9652 * Each element of that Array represents a row of data fields. The
9653 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
9654 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
9658 var RecordDef = Roo.data.Record.create([
9659 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
9660 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
9662 var myReader = new Roo.data.ArrayReader({
9663 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
9667 * This would consume an Array like this:
9669 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
9671 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
9673 * Create a new JsonReader
9674 * @param {Object} meta Metadata configuration options.
9675 * @param {Object} recordType Either an Array of field definition objects
9676 * as specified to {@link Roo.data.Record#create},
9677 * or an {@link Roo.data.Record} object
9678 * created using {@link Roo.data.Record#create}.
9680 Roo.data.ArrayReader = function(meta, recordType){
9681 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
9684 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
9686 * Create a data block containing Roo.data.Records from an XML document.
9687 * @param {Object} o An Array of row objects which represents the dataset.
9688 * @return {Object} data A data block which is used by an Roo.data.Store object as
9689 * a cache of Roo.data.Records.
9691 readRecords : function(o){
9692 var sid = this.meta ? this.meta.id : null;
9693 var recordType = this.recordType, fields = recordType.prototype.fields;
9696 for(var i = 0; i < root.length; i++){
9699 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
9700 for(var j = 0, jlen = fields.length; j < jlen; j++){
9701 var f = fields.items[j];
9702 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
9703 var v = n[k] !== undefined ? n[k] : f.defaultValue;
9707 var record = new recordType(values, id);
9709 records[records.length] = record;
9713 totalRecords : records.length
9722 * @class Roo.bootstrap.ComboBox
9723 * @extends Roo.bootstrap.TriggerField
9724 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9725 * @cfg {Boolean} append (true|false) default false
9726 * @cfg {Boolean} autoFocus (true|false) auto focus the first item, default true
9728 * Create a new ComboBox.
9729 * @param {Object} config Configuration options
9731 Roo.bootstrap.ComboBox = function(config){
9732 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9736 * Fires when the dropdown list is expanded
9737 * @param {Roo.bootstrap.ComboBox} combo This combo box
9742 * Fires when the dropdown list is collapsed
9743 * @param {Roo.bootstrap.ComboBox} combo This combo box
9747 * @event beforeselect
9748 * Fires before a list item is selected. Return false to cancel the selection.
9749 * @param {Roo.bootstrap.ComboBox} combo This combo box
9750 * @param {Roo.data.Record} record The data record returned from the underlying store
9751 * @param {Number} index The index of the selected item in the dropdown list
9753 'beforeselect' : true,
9756 * Fires when a list item is selected
9757 * @param {Roo.bootstrap.ComboBox} combo This combo box
9758 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9759 * @param {Number} index The index of the selected item in the dropdown list
9763 * @event beforequery
9764 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9765 * The event object passed has these properties:
9766 * @param {Roo.bootstrap.ComboBox} combo This combo box
9767 * @param {String} query The query
9768 * @param {Boolean} forceAll true to force "all" query
9769 * @param {Boolean} cancel true to cancel the query
9770 * @param {Object} e The query event object
9772 'beforequery': true,
9775 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9776 * @param {Roo.bootstrap.ComboBox} combo This combo box
9781 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9782 * @param {Roo.bootstrap.ComboBox} combo This combo box
9783 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9788 * Fires when the remove value from the combobox array
9789 * @param {Roo.bootstrap.ComboBox} combo This combo box
9796 this.selectedIndex = -1;
9797 if(this.mode == 'local'){
9798 if(config.queryDelay === undefined){
9799 this.queryDelay = 10;
9801 if(config.minChars === undefined){
9807 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9810 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9811 * rendering into an Roo.Editor, defaults to false)
9814 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9815 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9818 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9821 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9822 * the dropdown list (defaults to undefined, with no header element)
9826 * @cfg {String/Roo.Template} tpl The template to use to render the output
9830 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9832 listWidth: undefined,
9834 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9835 * mode = 'remote' or 'text' if mode = 'local')
9837 displayField: undefined,
9839 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9840 * mode = 'remote' or 'value' if mode = 'local').
9841 * Note: use of a valueField requires the user make a selection
9842 * in order for a value to be mapped.
9844 valueField: undefined,
9848 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9849 * field's data value (defaults to the underlying DOM element's name)
9851 hiddenName: undefined,
9853 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9857 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9859 selectedClass: 'active',
9862 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9866 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9867 * anchor positions (defaults to 'tl-bl')
9869 listAlign: 'tl-bl?',
9871 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9875 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9876 * query specified by the allQuery config option (defaults to 'query')
9878 triggerAction: 'query',
9880 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9881 * (defaults to 4, does not apply if editable = false)
9885 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9886 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9890 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9891 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9895 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9896 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9900 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9901 * when editable = true (defaults to false)
9903 selectOnFocus:false,
9905 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9907 queryParam: 'query',
9909 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9910 * when mode = 'remote' (defaults to 'Loading...')
9912 loadingText: 'Loading...',
9914 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9918 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9922 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9923 * traditional select (defaults to true)
9927 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9931 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9935 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9936 * listWidth has a higher value)
9940 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9941 * allow the user to set arbitrary text into the field (defaults to false)
9943 forceSelection:false,
9945 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9946 * if typeAhead = true (defaults to 250)
9948 typeAheadDelay : 250,
9950 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9951 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9953 valueNotFoundText : undefined,
9955 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9960 * @cfg {Boolean} disableClear Disable showing of clear button.
9962 disableClear : false,
9964 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9966 alwaysQuery : false,
9969 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9984 // element that contains real text value.. (when hidden is used..)
9987 initEvents: function(){
9990 throw "can not find store for combo";
9992 this.store = Roo.factory(this.store, Roo.data);
9996 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9999 if(this.hiddenName){
10001 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
10003 this.hiddenField.dom.value =
10004 this.hiddenValue !== undefined ? this.hiddenValue :
10005 this.value !== undefined ? this.value : '';
10007 // prevent input submission
10008 this.el.dom.removeAttribute('name');
10009 this.hiddenField.dom.setAttribute('name', this.hiddenName);
10014 // this.el.dom.setAttribute('autocomplete', 'off');
10017 var cls = 'x-combo-list';
10018 this.list = this.el.select('ul.dropdown-menu',true).first();
10020 //this.list = new Roo.Layer({
10021 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
10024 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
10025 this.list.setWidth(lw);
10027 this.list.on('mouseover', this.onViewOver, this);
10028 this.list.on('mousemove', this.onViewMove, this);
10030 this.list.on('scroll', this.onViewScroll, this);
10033 this.list.swallowEvent('mousewheel');
10034 this.assetHeight = 0;
10037 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
10038 this.assetHeight += this.header.getHeight();
10041 this.innerList = this.list.createChild({cls:cls+'-inner'});
10042 this.innerList.on('mouseover', this.onViewOver, this);
10043 this.innerList.on('mousemove', this.onViewMove, this);
10044 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10046 if(this.allowBlank && !this.pageSize && !this.disableClear){
10047 this.footer = this.list.createChild({cls:cls+'-ft'});
10048 this.pageTb = new Roo.Toolbar(this.footer);
10052 this.footer = this.list.createChild({cls:cls+'-ft'});
10053 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
10054 {pageSize: this.pageSize});
10058 if (this.pageTb && this.allowBlank && !this.disableClear) {
10060 this.pageTb.add(new Roo.Toolbar.Fill(), {
10061 cls: 'x-btn-icon x-btn-clear',
10063 handler: function()
10066 _this.clearValue();
10067 _this.onSelect(false, -1);
10072 this.assetHeight += this.footer.getHeight();
10077 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
10080 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
10081 singleSelect:true, store: this.store, selectedClass: this.selectedClass
10083 //this.view.wrapEl.setDisplayed(false);
10084 this.view.on('click', this.onViewClick, this);
10088 this.store.on('beforeload', this.onBeforeLoad, this);
10089 this.store.on('load', this.onLoad, this);
10090 this.store.on('loadexception', this.onLoadException, this);
10092 if(this.resizable){
10093 this.resizer = new Roo.Resizable(this.list, {
10094 pinned:true, handles:'se'
10096 this.resizer.on('resize', function(r, w, h){
10097 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
10098 this.listWidth = w;
10099 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
10100 this.restrictHeight();
10102 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
10105 if(!this.editable){
10106 this.editable = true;
10107 this.setEditable(false);
10112 if (typeof(this.events.add.listeners) != 'undefined') {
10114 this.addicon = this.wrap.createChild(
10115 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
10117 this.addicon.on('click', function(e) {
10118 this.fireEvent('add', this);
10121 if (typeof(this.events.edit.listeners) != 'undefined') {
10123 this.editicon = this.wrap.createChild(
10124 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
10125 if (this.addicon) {
10126 this.editicon.setStyle('margin-left', '40px');
10128 this.editicon.on('click', function(e) {
10130 // we fire even if inothing is selected..
10131 this.fireEvent('edit', this, this.lastData );
10137 this.keyNav = new Roo.KeyNav(this.inputEl(), {
10138 "up" : function(e){
10139 this.inKeyMode = true;
10143 "down" : function(e){
10144 if(!this.isExpanded()){
10145 this.onTriggerClick();
10147 this.inKeyMode = true;
10152 "enter" : function(e){
10153 // this.onViewClick();
10157 if(this.fireEvent("specialkey", this, e)){
10158 this.onViewClick(false);
10164 "esc" : function(e){
10168 "tab" : function(e){
10171 if(this.fireEvent("specialkey", this, e)){
10172 this.onViewClick(false);
10180 doRelay : function(foo, bar, hname){
10181 if(hname == 'down' || this.scope.isExpanded()){
10182 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
10191 this.queryDelay = Math.max(this.queryDelay || 10,
10192 this.mode == 'local' ? 10 : 250);
10195 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
10197 if(this.typeAhead){
10198 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
10200 if(this.editable !== false){
10201 this.inputEl().on("keyup", this.onKeyUp, this);
10203 if(this.forceSelection){
10204 this.inputEl().on('blur', this.doForce, this);
10208 this.choices = this.el.select('ul.select2-choices', true).first();
10209 this.searchField = this.el.select('ul li.select2-search-field', true).first();
10213 onDestroy : function(){
10215 this.view.setStore(null);
10216 this.view.el.removeAllListeners();
10217 this.view.el.remove();
10218 this.view.purgeListeners();
10221 this.list.dom.innerHTML = '';
10224 this.store.un('beforeload', this.onBeforeLoad, this);
10225 this.store.un('load', this.onLoad, this);
10226 this.store.un('loadexception', this.onLoadException, this);
10228 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
10232 fireKey : function(e){
10233 if(e.isNavKeyPress() && !this.list.isVisible()){
10234 this.fireEvent("specialkey", this, e);
10239 onResize: function(w, h){
10240 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
10242 // if(typeof w != 'number'){
10243 // // we do not handle it!?!?
10246 // var tw = this.trigger.getWidth();
10247 // // tw += this.addicon ? this.addicon.getWidth() : 0;
10248 // // tw += this.editicon ? this.editicon.getWidth() : 0;
10250 // this.inputEl().setWidth( this.adjustWidth('input', x));
10252 // //this.trigger.setStyle('left', x+'px');
10254 // if(this.list && this.listWidth === undefined){
10255 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
10256 // this.list.setWidth(lw);
10257 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
10265 * Allow or prevent the user from directly editing the field text. If false is passed,
10266 * the user will only be able to select from the items defined in the dropdown list. This method
10267 * is the runtime equivalent of setting the 'editable' config option at config time.
10268 * @param {Boolean} value True to allow the user to directly edit the field text
10270 setEditable : function(value){
10271 if(value == this.editable){
10274 this.editable = value;
10276 this.inputEl().dom.setAttribute('readOnly', true);
10277 this.inputEl().on('mousedown', this.onTriggerClick, this);
10278 this.inputEl().addClass('x-combo-noedit');
10280 this.inputEl().dom.setAttribute('readOnly', false);
10281 this.inputEl().un('mousedown', this.onTriggerClick, this);
10282 this.inputEl().removeClass('x-combo-noedit');
10288 onBeforeLoad : function(combo,opts){
10289 if(!this.hasFocus){
10293 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
10295 this.restrictHeight();
10296 this.selectedIndex = -1;
10300 onLoad : function(){
10302 this.hasQuery = false;
10304 if(!this.hasFocus){
10308 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10309 this.loading.hide();
10312 if(this.store.getCount() > 0){
10314 this.restrictHeight();
10315 if(this.lastQuery == this.allQuery){
10317 this.inputEl().dom.select();
10319 if(!this.selectByValue(this.value, true) && this.autoFocus){
10320 this.select(0, true);
10323 if(this.autoFocus){
10326 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
10327 this.taTask.delay(this.typeAheadDelay);
10331 this.onEmptyResults();
10337 onLoadException : function()
10339 this.hasQuery = false;
10341 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
10342 this.loading.hide();
10346 Roo.log(this.store.reader.jsonData);
10347 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
10349 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
10355 onTypeAhead : function(){
10356 if(this.store.getCount() > 0){
10357 var r = this.store.getAt(0);
10358 var newValue = r.data[this.displayField];
10359 var len = newValue.length;
10360 var selStart = this.getRawValue().length;
10362 if(selStart != len){
10363 this.setRawValue(newValue);
10364 this.selectText(selStart, newValue.length);
10370 onSelect : function(record, index){
10372 if(this.fireEvent('beforeselect', this, record, index) !== false){
10374 this.setFromData(index > -1 ? record.data : false);
10377 this.fireEvent('select', this, record, index);
10382 * Returns the currently selected field value or empty string if no value is set.
10383 * @return {String} value The selected value
10385 getValue : function(){
10388 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
10391 if(this.valueField){
10392 return typeof this.value != 'undefined' ? this.value : '';
10394 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
10399 * Clears any text/value currently set in the field
10401 clearValue : function(){
10402 if(this.hiddenField){
10403 this.hiddenField.dom.value = '';
10406 this.setRawValue('');
10407 this.lastSelectionText = '';
10412 * Sets the specified value into the field. If the value finds a match, the corresponding record text
10413 * will be displayed in the field. If the value does not match the data value of an existing item,
10414 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
10415 * Otherwise the field will be blank (although the value will still be set).
10416 * @param {String} value The value to match
10418 setValue : function(v){
10425 if(this.valueField){
10426 var r = this.findRecord(this.valueField, v);
10428 text = r.data[this.displayField];
10429 }else if(this.valueNotFoundText !== undefined){
10430 text = this.valueNotFoundText;
10433 this.lastSelectionText = text;
10434 if(this.hiddenField){
10435 this.hiddenField.dom.value = v;
10437 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
10441 * @property {Object} the last set data for the element
10446 * Sets the value of the field based on a object which is related to the record format for the store.
10447 * @param {Object} value the value to set as. or false on reset?
10449 setFromData : function(o){
10456 var dv = ''; // display value
10457 var vv = ''; // value value..
10459 if (this.displayField) {
10460 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10462 // this is an error condition!!!
10463 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10466 if(this.valueField){
10467 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
10470 if(this.hiddenField){
10471 this.hiddenField.dom.value = vv;
10473 this.lastSelectionText = dv;
10474 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10478 // no hidden field.. - we store the value in 'value', but still display
10479 // display field!!!!
10480 this.lastSelectionText = dv;
10481 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
10487 reset : function(){
10488 // overridden so that last data is reset..
10489 this.setValue(this.originalValue);
10490 this.clearInvalid();
10491 this.lastData = false;
10493 this.view.clearSelections();
10497 findRecord : function(prop, value){
10499 if(this.store.getCount() > 0){
10500 this.store.each(function(r){
10501 if(r.data[prop] == value){
10511 getName: function()
10513 // returns hidden if it's set..
10514 if (!this.rendered) {return ''};
10515 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
10519 onViewMove : function(e, t){
10520 this.inKeyMode = false;
10524 onViewOver : function(e, t){
10525 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
10528 var item = this.view.findItemFromChild(t);
10530 var index = this.view.indexOf(item);
10531 this.select(index, false);
10536 onViewClick : function(doFocus)
10538 var index = this.view.getSelectedIndexes()[0];
10539 var r = this.store.getAt(index);
10541 this.onSelect(r, index);
10543 if(doFocus !== false && !this.blockFocus){
10544 this.inputEl().focus();
10549 restrictHeight : function(){
10550 //this.innerList.dom.style.height = '';
10551 //var inner = this.innerList.dom;
10552 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
10553 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
10554 //this.list.beginUpdate();
10555 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
10556 this.list.alignTo(this.inputEl(), this.listAlign);
10557 //this.list.endUpdate();
10561 onEmptyResults : function(){
10566 * Returns true if the dropdown list is expanded, else false.
10568 isExpanded : function(){
10569 return this.list.isVisible();
10573 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
10574 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10575 * @param {String} value The data value of the item to select
10576 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10577 * selected item if it is not currently in view (defaults to true)
10578 * @return {Boolean} True if the value matched an item in the list, else false
10580 selectByValue : function(v, scrollIntoView){
10581 if(v !== undefined && v !== null){
10582 var r = this.findRecord(this.valueField || this.displayField, v);
10584 this.select(this.store.indexOf(r), scrollIntoView);
10592 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
10593 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
10594 * @param {Number} index The zero-based index of the list item to select
10595 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
10596 * selected item if it is not currently in view (defaults to true)
10598 select : function(index, scrollIntoView){
10599 this.selectedIndex = index;
10600 this.view.select(index);
10601 if(scrollIntoView !== false){
10602 var el = this.view.getNode(index);
10604 //this.innerList.scrollChildIntoView(el, false);
10611 selectNext : function(){
10612 var ct = this.store.getCount();
10614 if(this.selectedIndex == -1){
10616 }else if(this.selectedIndex < ct-1){
10617 this.select(this.selectedIndex+1);
10623 selectPrev : function(){
10624 var ct = this.store.getCount();
10626 if(this.selectedIndex == -1){
10628 }else if(this.selectedIndex != 0){
10629 this.select(this.selectedIndex-1);
10635 onKeyUp : function(e){
10636 if(this.editable !== false && !e.isSpecialKey()){
10637 this.lastKey = e.getKey();
10638 this.dqTask.delay(this.queryDelay);
10643 validateBlur : function(){
10644 return !this.list || !this.list.isVisible();
10648 initQuery : function(){
10649 this.doQuery(this.getRawValue());
10653 doForce : function(){
10654 if(this.inputEl().dom.value.length > 0){
10655 this.inputEl().dom.value =
10656 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
10662 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
10663 * query allowing the query action to be canceled if needed.
10664 * @param {String} query The SQL query to execute
10665 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
10666 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
10667 * saved in the current store (defaults to false)
10669 doQuery : function(q, forceAll){
10671 if(q === undefined || q === null){
10676 forceAll: forceAll,
10680 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
10685 forceAll = qe.forceAll;
10686 if(forceAll === true || (q.length >= this.minChars)){
10688 this.hasQuery = true;
10690 if(this.lastQuery != q || this.alwaysQuery){
10691 this.lastQuery = q;
10692 if(this.mode == 'local'){
10693 this.selectedIndex = -1;
10695 this.store.clearFilter();
10697 this.store.filter(this.displayField, q);
10701 this.store.baseParams[this.queryParam] = q;
10703 var options = {params : this.getParams(q)};
10706 options.add = true;
10707 options.params.start = this.page * this.pageSize;
10710 this.store.load(options);
10712 * this code will make the page width larger, at the beginning, the list not align correctly,
10713 * we should expand the list on onLoad
10714 * so command out it
10719 this.selectedIndex = -1;
10724 this.loadNext = false;
10728 getParams : function(q){
10730 //p[this.queryParam] = q;
10734 p.limit = this.pageSize;
10740 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10742 collapse : function(){
10743 if(!this.isExpanded()){
10748 Roo.get(document).un('mousedown', this.collapseIf, this);
10749 Roo.get(document).un('mousewheel', this.collapseIf, this);
10750 if (!this.editable) {
10751 Roo.get(document).un('keydown', this.listKeyPress, this);
10753 this.fireEvent('collapse', this);
10757 collapseIf : function(e){
10758 var in_combo = e.within(this.el);
10759 var in_list = e.within(this.list);
10761 if (in_combo || in_list) {
10762 //e.stopPropagation();
10771 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10773 expand : function(){
10775 if(this.isExpanded() || !this.hasFocus){
10779 this.list.alignTo(this.inputEl(), this.listAlign);
10781 Roo.get(document).on('mousedown', this.collapseIf, this);
10782 Roo.get(document).on('mousewheel', this.collapseIf, this);
10783 if (!this.editable) {
10784 Roo.get(document).on('keydown', this.listKeyPress, this);
10787 this.fireEvent('expand', this);
10791 // Implements the default empty TriggerField.onTriggerClick function
10792 onTriggerClick : function()
10794 Roo.log('trigger click');
10801 this.loadNext = false;
10803 if(this.isExpanded()){
10805 if (!this.blockFocus) {
10806 this.inputEl().focus();
10810 this.hasFocus = true;
10811 if(this.triggerAction == 'all') {
10812 this.doQuery(this.allQuery, true);
10814 this.doQuery(this.getRawValue());
10816 if (!this.blockFocus) {
10817 this.inputEl().focus();
10821 listKeyPress : function(e)
10823 //Roo.log('listkeypress');
10824 // scroll to first matching element based on key pres..
10825 if (e.isSpecialKey()) {
10828 var k = String.fromCharCode(e.getKey()).toUpperCase();
10831 var csel = this.view.getSelectedNodes();
10832 var cselitem = false;
10834 var ix = this.view.indexOf(csel[0]);
10835 cselitem = this.store.getAt(ix);
10836 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10842 this.store.each(function(v) {
10844 // start at existing selection.
10845 if (cselitem.id == v.id) {
10851 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10852 match = this.store.indexOf(v);
10858 if (match === false) {
10859 return true; // no more action?
10862 this.view.select(match);
10863 var sn = Roo.get(this.view.getSelectedNodes()[0])
10864 //sn.scrollIntoView(sn.dom.parentNode, false);
10867 onViewScroll : function(e, t){
10869 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10873 this.hasQuery = true;
10875 this.loading = this.list.select('.loading', true).first();
10877 if(this.loading === null){
10878 this.list.createChild({
10880 cls: 'loading select2-more-results select2-active',
10881 html: 'Loading more results...'
10884 this.loading = this.list.select('.loading', true).first();
10886 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10888 this.loading.hide();
10891 this.loading.show();
10896 this.loadNext = true;
10898 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10903 addItem : function(o)
10905 var dv = ''; // display value
10907 if (this.displayField) {
10908 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10910 // this is an error condition!!!
10911 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10918 var choice = this.choices.createChild({
10920 cls: 'select2-search-choice',
10929 cls: 'select2-search-choice-close',
10934 }, this.searchField);
10936 var close = choice.select('a.select2-search-choice-close', true).first()
10938 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10945 this.inputEl().dom.value = '';
10949 onRemoveItem : function(e, _self, o)
10951 e.preventDefault();
10952 var index = this.item.indexOf(o.data) * 1;
10955 Roo.log('not this item?!');
10959 this.item.splice(index, 1);
10964 this.fireEvent('remove', this, e);
10968 syncValue : function()
10970 if(!this.item.length){
10977 Roo.each(this.item, function(i){
10978 if(_this.valueField){
10979 value.push(i[_this.valueField]);
10986 this.value = value.join(',');
10988 if(this.hiddenField){
10989 this.hiddenField.dom.value = this.value;
10993 clearItem : function()
10995 if(!this.multiple){
11001 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
11011 * @cfg {Boolean} grow
11015 * @cfg {Number} growMin
11019 * @cfg {Number} growMax
11029 * Ext JS Library 1.1.1
11030 * Copyright(c) 2006-2007, Ext JS, LLC.
11032 * Originally Released Under LGPL - original licence link has changed is not relivant.
11035 * <script type="text/javascript">
11040 * @extends Roo.util.Observable
11041 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
11042 * This class also supports single and multi selection modes. <br>
11043 * Create a data model bound view:
11045 var store = new Roo.data.Store(...);
11047 var view = new Roo.View({
11049 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
11051 singleSelect: true,
11052 selectedClass: "ydataview-selected",
11056 // listen for node click?
11057 view.on("click", function(vw, index, node, e){
11058 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
11062 dataModel.load("foobar.xml");
11064 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
11066 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
11067 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
11069 * Note: old style constructor is still suported (container, template, config)
11072 * Create a new View
11073 * @param {Object} config The config object
11076 Roo.View = function(config, depreciated_tpl, depreciated_config){
11078 if (typeof(depreciated_tpl) == 'undefined') {
11079 // new way.. - universal constructor.
11080 Roo.apply(this, config);
11081 this.el = Roo.get(this.el);
11084 this.el = Roo.get(config);
11085 this.tpl = depreciated_tpl;
11086 Roo.apply(this, depreciated_config);
11088 this.wrapEl = this.el.wrap().wrap();
11089 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
11092 if(typeof(this.tpl) == "string"){
11093 this.tpl = new Roo.Template(this.tpl);
11095 // support xtype ctors..
11096 this.tpl = new Roo.factory(this.tpl, Roo);
11100 this.tpl.compile();
11108 * @event beforeclick
11109 * Fires before a click is processed. Returns false to cancel the default action.
11110 * @param {Roo.View} this
11111 * @param {Number} index The index of the target node
11112 * @param {HTMLElement} node The target node
11113 * @param {Roo.EventObject} e The raw event object
11115 "beforeclick" : true,
11118 * Fires when a template node is clicked.
11119 * @param {Roo.View} this
11120 * @param {Number} index The index of the target node
11121 * @param {HTMLElement} node The target node
11122 * @param {Roo.EventObject} e The raw event object
11127 * Fires when a template node is double clicked.
11128 * @param {Roo.View} this
11129 * @param {Number} index The index of the target node
11130 * @param {HTMLElement} node The target node
11131 * @param {Roo.EventObject} e The raw event object
11135 * @event contextmenu
11136 * Fires when a template node is right clicked.
11137 * @param {Roo.View} this
11138 * @param {Number} index The index of the target node
11139 * @param {HTMLElement} node The target node
11140 * @param {Roo.EventObject} e The raw event object
11142 "contextmenu" : true,
11144 * @event selectionchange
11145 * Fires when the selected nodes change.
11146 * @param {Roo.View} this
11147 * @param {Array} selections Array of the selected nodes
11149 "selectionchange" : true,
11152 * @event beforeselect
11153 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
11154 * @param {Roo.View} this
11155 * @param {HTMLElement} node The node to be selected
11156 * @param {Array} selections Array of currently selected nodes
11158 "beforeselect" : true,
11160 * @event preparedata
11161 * Fires on every row to render, to allow you to change the data.
11162 * @param {Roo.View} this
11163 * @param {Object} data to be rendered (change this)
11165 "preparedata" : true
11173 "click": this.onClick,
11174 "dblclick": this.onDblClick,
11175 "contextmenu": this.onContextMenu,
11179 this.selections = [];
11181 this.cmp = new Roo.CompositeElementLite([]);
11183 this.store = Roo.factory(this.store, Roo.data);
11184 this.setStore(this.store, true);
11187 if ( this.footer && this.footer.xtype) {
11189 var fctr = this.wrapEl.appendChild(document.createElement("div"));
11191 this.footer.dataSource = this.store
11192 this.footer.container = fctr;
11193 this.footer = Roo.factory(this.footer, Roo);
11194 fctr.insertFirst(this.el);
11196 // this is a bit insane - as the paging toolbar seems to detach the el..
11197 // dom.parentNode.parentNode.parentNode
11198 // they get detached?
11202 Roo.View.superclass.constructor.call(this);
11207 Roo.extend(Roo.View, Roo.util.Observable, {
11210 * @cfg {Roo.data.Store} store Data store to load data from.
11215 * @cfg {String|Roo.Element} el The container element.
11220 * @cfg {String|Roo.Template} tpl The template used by this View
11224 * @cfg {String} dataName the named area of the template to use as the data area
11225 * Works with domtemplates roo-name="name"
11229 * @cfg {String} selectedClass The css class to add to selected nodes
11231 selectedClass : "x-view-selected",
11233 * @cfg {String} emptyText The empty text to show when nothing is loaded.
11238 * @cfg {String} text to display on mask (default Loading)
11242 * @cfg {Boolean} multiSelect Allow multiple selection
11244 multiSelect : false,
11246 * @cfg {Boolean} singleSelect Allow single selection
11248 singleSelect: false,
11251 * @cfg {Boolean} toggleSelect - selecting
11253 toggleSelect : false,
11256 * Returns the element this view is bound to.
11257 * @return {Roo.Element}
11259 getEl : function(){
11260 return this.wrapEl;
11266 * Refreshes the view. - called by datachanged on the store. - do not call directly.
11268 refresh : function(){
11269 Roo.log('refresh');
11272 // if we are using something like 'domtemplate', then
11273 // the what gets used is:
11274 // t.applySubtemplate(NAME, data, wrapping data..)
11275 // the outer template then get' applied with
11276 // the store 'extra data'
11277 // and the body get's added to the
11278 // roo-name="data" node?
11279 // <span class='roo-tpl-{name}'></span> ?????
11283 this.clearSelections();
11284 this.el.update("");
11286 var records = this.store.getRange();
11287 if(records.length < 1) {
11289 // is this valid?? = should it render a template??
11291 this.el.update(this.emptyText);
11295 if (this.dataName) {
11296 this.el.update(t.apply(this.store.meta)); //????
11297 el = this.el.child('.roo-tpl-' + this.dataName);
11300 for(var i = 0, len = records.length; i < len; i++){
11301 var data = this.prepareData(records[i].data, i, records[i]);
11302 this.fireEvent("preparedata", this, data, i, records[i]);
11303 html[html.length] = Roo.util.Format.trim(
11305 t.applySubtemplate(this.dataName, data, this.store.meta) :
11312 el.update(html.join(""));
11313 this.nodes = el.dom.childNodes;
11314 this.updateIndexes(0);
11319 * Function to override to reformat the data that is sent to
11320 * the template for each node.
11321 * DEPRICATED - use the preparedata event handler.
11322 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
11323 * a JSON object for an UpdateManager bound view).
11325 prepareData : function(data, index, record)
11327 this.fireEvent("preparedata", this, data, index, record);
11331 onUpdate : function(ds, record){
11332 Roo.log('on update');
11333 this.clearSelections();
11334 var index = this.store.indexOf(record);
11335 var n = this.nodes[index];
11336 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
11337 n.parentNode.removeChild(n);
11338 this.updateIndexes(index, index);
11344 onAdd : function(ds, records, index)
11346 Roo.log(['on Add', ds, records, index] );
11347 this.clearSelections();
11348 if(this.nodes.length == 0){
11352 var n = this.nodes[index];
11353 for(var i = 0, len = records.length; i < len; i++){
11354 var d = this.prepareData(records[i].data, i, records[i]);
11356 this.tpl.insertBefore(n, d);
11359 this.tpl.append(this.el, d);
11362 this.updateIndexes(index);
11365 onRemove : function(ds, record, index){
11366 Roo.log('onRemove');
11367 this.clearSelections();
11368 var el = this.dataName ?
11369 this.el.child('.roo-tpl-' + this.dataName) :
11372 el.dom.removeChild(this.nodes[index]);
11373 this.updateIndexes(index);
11377 * Refresh an individual node.
11378 * @param {Number} index
11380 refreshNode : function(index){
11381 this.onUpdate(this.store, this.store.getAt(index));
11384 updateIndexes : function(startIndex, endIndex){
11385 var ns = this.nodes;
11386 startIndex = startIndex || 0;
11387 endIndex = endIndex || ns.length - 1;
11388 for(var i = startIndex; i <= endIndex; i++){
11389 ns[i].nodeIndex = i;
11394 * Changes the data store this view uses and refresh the view.
11395 * @param {Store} store
11397 setStore : function(store, initial){
11398 if(!initial && this.store){
11399 this.store.un("datachanged", this.refresh);
11400 this.store.un("add", this.onAdd);
11401 this.store.un("remove", this.onRemove);
11402 this.store.un("update", this.onUpdate);
11403 this.store.un("clear", this.refresh);
11404 this.store.un("beforeload", this.onBeforeLoad);
11405 this.store.un("load", this.onLoad);
11406 this.store.un("loadexception", this.onLoad);
11410 store.on("datachanged", this.refresh, this);
11411 store.on("add", this.onAdd, this);
11412 store.on("remove", this.onRemove, this);
11413 store.on("update", this.onUpdate, this);
11414 store.on("clear", this.refresh, this);
11415 store.on("beforeload", this.onBeforeLoad, this);
11416 store.on("load", this.onLoad, this);
11417 store.on("loadexception", this.onLoad, this);
11425 * onbeforeLoad - masks the loading area.
11428 onBeforeLoad : function(store,opts)
11430 Roo.log('onBeforeLoad');
11432 this.el.update("");
11434 this.el.mask(this.mask ? this.mask : "Loading" );
11436 onLoad : function ()
11443 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
11444 * @param {HTMLElement} node
11445 * @return {HTMLElement} The template node
11447 findItemFromChild : function(node){
11448 var el = this.dataName ?
11449 this.el.child('.roo-tpl-' + this.dataName,true) :
11452 if(!node || node.parentNode == el){
11455 var p = node.parentNode;
11456 while(p && p != el){
11457 if(p.parentNode == el){
11466 onClick : function(e){
11467 var item = this.findItemFromChild(e.getTarget());
11469 var index = this.indexOf(item);
11470 if(this.onItemClick(item, index, e) !== false){
11471 this.fireEvent("click", this, index, item, e);
11474 this.clearSelections();
11479 onContextMenu : function(e){
11480 var item = this.findItemFromChild(e.getTarget());
11482 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
11487 onDblClick : function(e){
11488 var item = this.findItemFromChild(e.getTarget());
11490 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
11494 onItemClick : function(item, index, e)
11496 if(this.fireEvent("beforeclick", this, index, item, e) === false){
11499 if (this.toggleSelect) {
11500 var m = this.isSelected(item) ? 'unselect' : 'select';
11503 _t[m](item, true, false);
11506 if(this.multiSelect || this.singleSelect){
11507 if(this.multiSelect && e.shiftKey && this.lastSelection){
11508 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
11510 this.select(item, this.multiSelect && e.ctrlKey);
11511 this.lastSelection = item;
11513 e.preventDefault();
11519 * Get the number of selected nodes.
11522 getSelectionCount : function(){
11523 return this.selections.length;
11527 * Get the currently selected nodes.
11528 * @return {Array} An array of HTMLElements
11530 getSelectedNodes : function(){
11531 return this.selections;
11535 * Get the indexes of the selected nodes.
11538 getSelectedIndexes : function(){
11539 var indexes = [], s = this.selections;
11540 for(var i = 0, len = s.length; i < len; i++){
11541 indexes.push(s[i].nodeIndex);
11547 * Clear all selections
11548 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
11550 clearSelections : function(suppressEvent){
11551 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
11552 this.cmp.elements = this.selections;
11553 this.cmp.removeClass(this.selectedClass);
11554 this.selections = [];
11555 if(!suppressEvent){
11556 this.fireEvent("selectionchange", this, this.selections);
11562 * Returns true if the passed node is selected
11563 * @param {HTMLElement/Number} node The node or node index
11564 * @return {Boolean}
11566 isSelected : function(node){
11567 var s = this.selections;
11571 node = this.getNode(node);
11572 return s.indexOf(node) !== -1;
11577 * @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
11578 * @param {Boolean} keepExisting (optional) true to keep existing selections
11579 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11581 select : function(nodeInfo, keepExisting, suppressEvent){
11582 if(nodeInfo instanceof Array){
11584 this.clearSelections(true);
11586 for(var i = 0, len = nodeInfo.length; i < len; i++){
11587 this.select(nodeInfo[i], true, true);
11591 var node = this.getNode(nodeInfo);
11592 if(!node || this.isSelected(node)){
11593 return; // already selected.
11596 this.clearSelections(true);
11598 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
11599 Roo.fly(node).addClass(this.selectedClass);
11600 this.selections.push(node);
11601 if(!suppressEvent){
11602 this.fireEvent("selectionchange", this, this.selections);
11610 * @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
11611 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
11612 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
11614 unselect : function(nodeInfo, keepExisting, suppressEvent)
11616 if(nodeInfo instanceof Array){
11617 Roo.each(this.selections, function(s) {
11618 this.unselect(s, nodeInfo);
11622 var node = this.getNode(nodeInfo);
11623 if(!node || !this.isSelected(node)){
11624 Roo.log("not selected");
11625 return; // not selected.
11629 Roo.each(this.selections, function(s) {
11631 Roo.fly(node).removeClass(this.selectedClass);
11638 this.selections= ns;
11639 this.fireEvent("selectionchange", this, this.selections);
11643 * Gets a template node.
11644 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11645 * @return {HTMLElement} The node or null if it wasn't found
11647 getNode : function(nodeInfo){
11648 if(typeof nodeInfo == "string"){
11649 return document.getElementById(nodeInfo);
11650 }else if(typeof nodeInfo == "number"){
11651 return this.nodes[nodeInfo];
11657 * Gets a range template nodes.
11658 * @param {Number} startIndex
11659 * @param {Number} endIndex
11660 * @return {Array} An array of nodes
11662 getNodes : function(start, end){
11663 var ns = this.nodes;
11664 start = start || 0;
11665 end = typeof end == "undefined" ? ns.length - 1 : end;
11668 for(var i = start; i <= end; i++){
11672 for(var i = start; i >= end; i--){
11680 * Finds the index of the passed node
11681 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
11682 * @return {Number} The index of the node or -1
11684 indexOf : function(node){
11685 node = this.getNode(node);
11686 if(typeof node.nodeIndex == "number"){
11687 return node.nodeIndex;
11689 var ns = this.nodes;
11690 for(var i = 0, len = ns.length; i < len; i++){
11701 * based on jquery fullcalendar
11705 Roo.bootstrap = Roo.bootstrap || {};
11707 * @class Roo.bootstrap.Calendar
11708 * @extends Roo.bootstrap.Component
11709 * Bootstrap Calendar class
11710 * @cfg {Boolean} loadMask (true|false) default false
11711 * @cfg {Object} header generate the user specific header of the calendar, default false
11714 * Create a new Container
11715 * @param {Object} config The config object
11720 Roo.bootstrap.Calendar = function(config){
11721 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
11725 * Fires when a date is selected
11726 * @param {DatePicker} this
11727 * @param {Date} date The selected date
11731 * @event monthchange
11732 * Fires when the displayed month changes
11733 * @param {DatePicker} this
11734 * @param {Date} date The selected month
11736 'monthchange': true,
11738 * @event evententer
11739 * Fires when mouse over an event
11740 * @param {Calendar} this
11741 * @param {event} Event
11743 'evententer': true,
11745 * @event eventleave
11746 * Fires when the mouse leaves an
11747 * @param {Calendar} this
11750 'eventleave': true,
11752 * @event eventclick
11753 * Fires when the mouse click an
11754 * @param {Calendar} this
11763 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11766 * @cfg {Number} startDay
11767 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11775 getAutoCreate : function(){
11778 var fc_button = function(name, corner, style, content ) {
11779 return Roo.apply({},{
11781 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11783 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11786 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11797 style : 'width:100%',
11804 cls : 'fc-header-left',
11806 fc_button('prev', 'left', 'arrow', '‹' ),
11807 fc_button('next', 'right', 'arrow', '›' ),
11808 { tag: 'span', cls: 'fc-header-space' },
11809 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11817 cls : 'fc-header-center',
11821 cls: 'fc-header-title',
11824 html : 'month / year'
11832 cls : 'fc-header-right',
11834 /* fc_button('month', 'left', '', 'month' ),
11835 fc_button('week', '', '', 'week' ),
11836 fc_button('day', 'right', '', 'day' )
11848 header = this.header;
11851 var cal_heads = function() {
11853 // fixme - handle this.
11855 for (var i =0; i < Date.dayNames.length; i++) {
11856 var d = Date.dayNames[i];
11859 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11860 html : d.substring(0,3)
11864 ret[0].cls += ' fc-first';
11865 ret[6].cls += ' fc-last';
11868 var cal_cell = function(n) {
11871 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11876 cls: 'fc-day-number',
11880 cls: 'fc-day-content',
11884 style: 'position: relative;' // height: 17px;
11896 var cal_rows = function() {
11899 for (var r = 0; r < 6; r++) {
11906 for (var i =0; i < Date.dayNames.length; i++) {
11907 var d = Date.dayNames[i];
11908 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11911 row.cn[0].cls+=' fc-first';
11912 row.cn[0].cn[0].style = 'min-height:90px';
11913 row.cn[6].cls+=' fc-last';
11917 ret[0].cls += ' fc-first';
11918 ret[4].cls += ' fc-prev-last';
11919 ret[5].cls += ' fc-last';
11926 cls: 'fc-border-separate',
11927 style : 'width:100%',
11935 cls : 'fc-first fc-last',
11953 cls : 'fc-content',
11954 style : "position: relative;",
11957 cls : 'fc-view fc-view-month fc-grid',
11958 style : 'position: relative',
11959 unselectable : 'on',
11962 cls : 'fc-event-container',
11963 style : 'position:absolute;z-index:8;top:0;left:0;'
11981 initEvents : function()
11984 throw "can not find store for calendar";
11990 style: "text-align:center",
11994 style: "background-color:white;width:50%;margin:250 auto",
11998 src: Roo.rootURL + '/images/ux/lightbox/loading.gif'
12009 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
12011 var size = this.el.select('.fc-content', true).first().getSize();
12012 this.maskEl.setSize(size.width, size.height);
12013 this.maskEl.enableDisplayMode("block");
12014 if(!this.loadMask){
12015 this.maskEl.hide();
12018 this.store = Roo.factory(this.store, Roo.data);
12019 this.store.on('load', this.onLoad, this);
12020 this.store.on('beforeload', this.onBeforeLoad, this);
12024 this.cells = this.el.select('.fc-day',true);
12025 //Roo.log(this.cells);
12026 this.textNodes = this.el.query('.fc-day-number');
12027 this.cells.addClassOnOver('fc-state-hover');
12029 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
12030 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
12031 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
12032 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
12034 this.on('monthchange', this.onMonthChange, this);
12036 this.update(new Date().clearTime());
12039 resize : function() {
12040 var sz = this.el.getSize();
12042 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
12043 this.el.select('.fc-day-content div',true).setHeight(34);
12048 showPrevMonth : function(e){
12049 this.update(this.activeDate.add("mo", -1));
12051 showToday : function(e){
12052 this.update(new Date().clearTime());
12055 showNextMonth : function(e){
12056 this.update(this.activeDate.add("mo", 1));
12060 showPrevYear : function(){
12061 this.update(this.activeDate.add("y", -1));
12065 showNextYear : function(){
12066 this.update(this.activeDate.add("y", 1));
12071 update : function(date)
12073 var vd = this.activeDate;
12074 this.activeDate = date;
12075 // if(vd && this.el){
12076 // var t = date.getTime();
12077 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
12078 // Roo.log('using add remove');
12080 // this.fireEvent('monthchange', this, date);
12082 // this.cells.removeClass("fc-state-highlight");
12083 // this.cells.each(function(c){
12084 // if(c.dateValue == t){
12085 // c.addClass("fc-state-highlight");
12086 // setTimeout(function(){
12087 // try{c.dom.firstChild.focus();}catch(e){}
12097 var days = date.getDaysInMonth();
12099 var firstOfMonth = date.getFirstDateOfMonth();
12100 var startingPos = firstOfMonth.getDay()-this.startDay;
12102 if(startingPos < this.startDay){
12106 var pm = date.add(Date.MONTH, -1);
12107 var prevStart = pm.getDaysInMonth()-startingPos;
12109 this.cells = this.el.select('.fc-day',true);
12110 this.textNodes = this.el.query('.fc-day-number');
12111 this.cells.addClassOnOver('fc-state-hover');
12113 var cells = this.cells.elements;
12114 var textEls = this.textNodes;
12116 Roo.each(cells, function(cell){
12117 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
12120 days += startingPos;
12122 // convert everything to numbers so it's fast
12123 var day = 86400000;
12124 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
12127 //Roo.log(prevStart);
12129 var today = new Date().clearTime().getTime();
12130 var sel = date.clearTime().getTime();
12131 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
12132 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
12133 var ddMatch = this.disabledDatesRE;
12134 var ddText = this.disabledDatesText;
12135 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
12136 var ddaysText = this.disabledDaysText;
12137 var format = this.format;
12139 var setCellClass = function(cal, cell){
12143 //Roo.log('set Cell Class');
12145 var t = d.getTime();
12149 cell.dateValue = t;
12151 cell.className += " fc-today";
12152 cell.className += " fc-state-highlight";
12153 cell.title = cal.todayText;
12156 // disable highlight in other month..
12157 //cell.className += " fc-state-highlight";
12162 cell.className = " fc-state-disabled";
12163 cell.title = cal.minText;
12167 cell.className = " fc-state-disabled";
12168 cell.title = cal.maxText;
12172 if(ddays.indexOf(d.getDay()) != -1){
12173 cell.title = ddaysText;
12174 cell.className = " fc-state-disabled";
12177 if(ddMatch && format){
12178 var fvalue = d.dateFormat(format);
12179 if(ddMatch.test(fvalue)){
12180 cell.title = ddText.replace("%0", fvalue);
12181 cell.className = " fc-state-disabled";
12185 if (!cell.initialClassName) {
12186 cell.initialClassName = cell.dom.className;
12189 cell.dom.className = cell.initialClassName + ' ' + cell.className;
12194 for(; i < startingPos; i++) {
12195 textEls[i].innerHTML = (++prevStart);
12196 d.setDate(d.getDate()+1);
12198 cells[i].className = "fc-past fc-other-month";
12199 setCellClass(this, cells[i]);
12204 for(; i < days; i++){
12205 intDay = i - startingPos + 1;
12206 textEls[i].innerHTML = (intDay);
12207 d.setDate(d.getDate()+1);
12209 cells[i].className = ''; // "x-date-active";
12210 setCellClass(this, cells[i]);
12214 for(; i < 42; i++) {
12215 textEls[i].innerHTML = (++extraDays);
12216 d.setDate(d.getDate()+1);
12218 cells[i].className = "fc-future fc-other-month";
12219 setCellClass(this, cells[i]);
12222 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
12224 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
12226 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
12227 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
12229 if(totalRows != 6){
12230 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
12231 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
12234 this.fireEvent('monthchange', this, date);
12238 if(!this.internalRender){
12239 var main = this.el.dom.firstChild;
12240 var w = main.offsetWidth;
12241 this.el.setWidth(w + this.el.getBorderWidth("lr"));
12242 Roo.fly(main).setWidth(w);
12243 this.internalRender = true;
12244 // opera does not respect the auto grow header center column
12245 // then, after it gets a width opera refuses to recalculate
12246 // without a second pass
12247 if(Roo.isOpera && !this.secondPass){
12248 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
12249 this.secondPass = true;
12250 this.update.defer(10, this, [date]);
12257 findCell : function(dt) {
12258 dt = dt.clearTime().getTime();
12260 this.cells.each(function(c){
12261 //Roo.log("check " +c.dateValue + '?=' + dt);
12262 if(c.dateValue == dt){
12272 findCells : function(ev) {
12273 var s = ev.start.clone().clearTime().getTime();
12275 var e= ev.end.clone().clearTime().getTime();
12278 this.cells.each(function(c){
12279 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
12281 if(c.dateValue > e){
12284 if(c.dateValue < s){
12293 // findBestRow: function(cells)
12297 // for (var i =0 ; i < cells.length;i++) {
12298 // ret = Math.max(cells[i].rows || 0,ret);
12305 addItem : function(ev)
12307 // look for vertical location slot in
12308 var cells = this.findCells(ev);
12310 // ev.row = this.findBestRow(cells);
12312 // work out the location.
12316 for(var i =0; i < cells.length; i++) {
12318 cells[i].row = cells[0].row;
12321 cells[i].row = cells[i].row + 1;
12331 if (crow.start.getY() == cells[i].getY()) {
12333 crow.end = cells[i];
12350 cells[0].events.push(ev);
12352 this.calevents.push(ev);
12355 clearEvents: function() {
12357 if(!this.calevents){
12361 Roo.each(this.cells.elements, function(c){
12367 Roo.each(this.calevents, function(e) {
12368 Roo.each(e.els, function(el) {
12369 el.un('mouseenter' ,this.onEventEnter, this);
12370 el.un('mouseleave' ,this.onEventLeave, this);
12375 Roo.each(Roo.select('.fc-more-event', true).elements, function(e){
12381 renderEvents: function()
12385 this.cells.each(function(c) {
12394 if(c.row != c.events.length){
12395 r = 4 - (4 - (c.row - c.events.length));
12398 c.events = ev.slice(0, r);
12399 c.more = ev.slice(r);
12401 if(c.more.length && c.more.length == 1){
12402 c.events.push(c.more.pop());
12405 c.row = (c.row - ev.length) + c.events.length + ((c.more.length) ? 1 : 0);
12409 this.cells.each(function(c) {
12411 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.row * 20));
12414 for (var e = 0; e < c.events.length; e++){
12415 var ev = c.events[e];
12416 var rows = ev.rows;
12418 for(var i = 0; i < rows.length; i++) {
12420 // how many rows should it span..
12423 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
12424 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
12426 unselectable : "on",
12429 cls: 'fc-event-inner',
12433 // cls: 'fc-event-time',
12434 // html : cells.length > 1 ? '' : ev.time
12438 cls: 'fc-event-title',
12439 html : String.format('{0}', ev.title)
12446 cls: 'ui-resizable-handle ui-resizable-e',
12447 html : '  '
12454 cfg.cls += ' fc-event-start';
12456 if ((i+1) == rows.length) {
12457 cfg.cls += ' fc-event-end';
12460 var ctr = _this.el.select('.fc-event-container',true).first();
12461 var cg = ctr.createChild(cfg);
12463 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
12464 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
12466 var r = (c.more.length) ? 1 : 0;
12467 cg.setXY([sbox.x +2, sbox.y + ((c.row - c.events.length - r + e) * 20)]);
12468 cg.setWidth(ebox.right - sbox.x -2);
12470 cg.on('mouseenter' ,_this.onEventEnter, _this, ev);
12471 cg.on('mouseleave' ,_this.onEventLeave, _this, ev);
12472 cg.on('click', _this.onEventClick, _this, ev);
12483 cls : 'fc-more-event roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable fc-event-start fc-event-end',
12484 style : 'position: absolute',
12485 unselectable : "on",
12488 cls: 'fc-event-inner',
12492 cls: 'fc-event-title',
12500 cls: 'ui-resizable-handle ui-resizable-e',
12501 html : '  '
12507 var ctr = _this.el.select('.fc-event-container',true).first();
12508 var cg = ctr.createChild(cfg);
12510 var sbox = c.select('.fc-day-content',true).first().getBox();
12511 var ebox = c.select('.fc-day-content',true).first().getBox();
12513 cg.setXY([sbox.x +2, sbox.y +((c.row - 1) * 20)]);
12514 cg.setWidth(ebox.right - sbox.x -2);
12516 cg.on('click', _this.onMoreEventClick, _this, c.more);
12526 onEventEnter: function (e, el,event,d) {
12527 this.fireEvent('evententer', this, el, event);
12530 onEventLeave: function (e, el,event,d) {
12531 this.fireEvent('eventleave', this, el, event);
12534 onEventClick: function (e, el,event,d) {
12535 this.fireEvent('eventclick', this, el, event);
12538 onMonthChange: function () {
12542 onMoreEventClick: function(e, el, more)
12546 this.calpopover.placement = 'right';
12547 this.calpopover.setTitle('More');
12549 this.calpopover.setContent('');
12551 var ctr = this.calpopover.el.select('.popover-content', true).first();
12553 Roo.each(more, function(m){
12555 cls : 'fc-event-hori fc-event-draggable',
12558 var cg = ctr.createChild(cfg);
12560 cg.on('click', _this.onEventClick, _this, m);
12563 this.calpopover.show(el);
12568 onLoad: function ()
12570 this.calevents = [];
12573 if(this.store.getCount() > 0){
12574 this.store.data.each(function(d){
12577 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
12578 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
12579 time : d.data.start_time,
12580 title : d.data.title,
12581 description : d.data.description,
12582 venue : d.data.venue
12587 this.renderEvents();
12589 if(this.calevents.length && this.loadMask){
12590 this.maskEl.hide();
12594 onBeforeLoad: function()
12596 this.clearEvents();
12598 this.maskEl.show();
12612 * @class Roo.bootstrap.Popover
12613 * @extends Roo.bootstrap.Component
12614 * Bootstrap Popover class
12615 * @cfg {String} html contents of the popover (or false to use children..)
12616 * @cfg {String} title of popover (or false to hide)
12617 * @cfg {String} placement how it is placed
12618 * @cfg {String} trigger click || hover (or false to trigger manually)
12619 * @cfg {String} over what (parent or false to trigger manually.)
12622 * Create a new Popover
12623 * @param {Object} config The config object
12626 Roo.bootstrap.Popover = function(config){
12627 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
12630 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
12632 title: 'Fill in a title',
12635 placement : 'right',
12636 trigger : 'hover', // hover
12640 can_build_overlaid : false,
12642 getChildContainer : function()
12644 return this.el.select('.popover-content',true).first();
12647 getAutoCreate : function(){
12648 Roo.log('make popover?');
12650 cls : 'popover roo-dynamic',
12651 style: 'display:block',
12657 cls : 'popover-inner',
12661 cls: 'popover-title',
12665 cls : 'popover-content',
12676 setTitle: function(str)
12678 this.el.select('.popover-title',true).first().dom.innerHTML = str;
12680 setContent: function(str)
12682 this.el.select('.popover-content',true).first().dom.innerHTML = str;
12684 // as it get's added to the bottom of the page.
12685 onRender : function(ct, position)
12687 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
12689 var cfg = Roo.apply({}, this.getAutoCreate());
12693 cfg.cls += ' ' + this.cls;
12696 cfg.style = this.style;
12698 Roo.log("adding to ")
12699 this.el = Roo.get(document.body).createChild(cfg, position);
12705 initEvents : function()
12707 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
12708 this.el.enableDisplayMode('block');
12710 if (this.over === false) {
12713 if (this.triggers === false) {
12716 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12717 var triggers = this.trigger ? this.trigger.split(' ') : [];
12718 Roo.each(triggers, function(trigger) {
12720 if (trigger == 'click') {
12721 on_el.on('click', this.toggle, this);
12722 } else if (trigger != 'manual') {
12723 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
12724 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
12726 on_el.on(eventIn ,this.enter, this);
12727 on_el.on(eventOut, this.leave, this);
12738 toggle : function () {
12739 this.hoverState == 'in' ? this.leave() : this.enter();
12742 enter : function () {
12745 clearTimeout(this.timeout);
12747 this.hoverState = 'in'
12749 if (!this.delay || !this.delay.show) {
12754 this.timeout = setTimeout(function () {
12755 if (_t.hoverState == 'in') {
12758 }, this.delay.show)
12760 leave : function() {
12761 clearTimeout(this.timeout);
12763 this.hoverState = 'out'
12765 if (!this.delay || !this.delay.hide) {
12770 this.timeout = setTimeout(function () {
12771 if (_t.hoverState == 'out') {
12774 }, this.delay.hide)
12777 show : function (on_el)
12780 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
12783 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
12784 if (this.html !== false) {
12785 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
12787 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
12788 if (!this.title.length) {
12789 this.el.select('.popover-title',true).hide();
12792 var placement = typeof this.placement == 'function' ?
12793 this.placement.call(this, this.el, on_el) :
12796 var autoToken = /\s?auto?\s?/i;
12797 var autoPlace = autoToken.test(placement);
12799 placement = placement.replace(autoToken, '') || 'top';
12803 //this.el.setXY([0,0]);
12805 this.el.dom.style.display='block';
12806 this.el.addClass(placement);
12808 //this.el.appendTo(on_el);
12810 var p = this.getPosition();
12811 var box = this.el.getBox();
12816 var align = Roo.bootstrap.Popover.alignment[placement]
12817 this.el.alignTo(on_el, align[0],align[1]);
12818 //var arrow = this.el.select('.arrow',true).first();
12819 //arrow.set(align[2],
12821 this.el.addClass('in');
12822 this.hoverState = null;
12824 if (this.el.hasClass('fade')) {
12831 this.el.setXY([0,0]);
12832 this.el.removeClass('in');
12839 Roo.bootstrap.Popover.alignment = {
12840 'left' : ['r-l', [-10,0], 'right'],
12841 'right' : ['l-r', [10,0], 'left'],
12842 'bottom' : ['t-b', [0,10], 'top'],
12843 'top' : [ 'b-t', [0,-10], 'bottom']
12854 * @class Roo.bootstrap.Progress
12855 * @extends Roo.bootstrap.Component
12856 * Bootstrap Progress class
12857 * @cfg {Boolean} striped striped of the progress bar
12858 * @cfg {Boolean} active animated of the progress bar
12862 * Create a new Progress
12863 * @param {Object} config The config object
12866 Roo.bootstrap.Progress = function(config){
12867 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12870 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12875 getAutoCreate : function(){
12883 cfg.cls += ' progress-striped';
12887 cfg.cls += ' active';
12906 * @class Roo.bootstrap.ProgressBar
12907 * @extends Roo.bootstrap.Component
12908 * Bootstrap ProgressBar class
12909 * @cfg {Number} aria_valuenow aria-value now
12910 * @cfg {Number} aria_valuemin aria-value min
12911 * @cfg {Number} aria_valuemax aria-value max
12912 * @cfg {String} label label for the progress bar
12913 * @cfg {String} panel (success | info | warning | danger )
12914 * @cfg {String} role role of the progress bar
12915 * @cfg {String} sr_only text
12919 * Create a new ProgressBar
12920 * @param {Object} config The config object
12923 Roo.bootstrap.ProgressBar = function(config){
12924 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12927 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12931 aria_valuemax : 100,
12937 getAutoCreate : function()
12942 cls: 'progress-bar',
12943 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12955 cfg.role = this.role;
12958 if(this.aria_valuenow){
12959 cfg['aria-valuenow'] = this.aria_valuenow;
12962 if(this.aria_valuemin){
12963 cfg['aria-valuemin'] = this.aria_valuemin;
12966 if(this.aria_valuemax){
12967 cfg['aria-valuemax'] = this.aria_valuemax;
12970 if(this.label && !this.sr_only){
12971 cfg.html = this.label;
12975 cfg.cls += ' progress-bar-' + this.panel;
12981 update : function(aria_valuenow)
12983 this.aria_valuenow = aria_valuenow;
12985 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
13000 * @class Roo.bootstrap.TabPanel
13001 * @extends Roo.bootstrap.Component
13002 * Bootstrap TabPanel class
13003 * @cfg {Boolean} active panel active
13004 * @cfg {String} html panel content
13005 * @cfg {String} tabId tab relate id
13006 * @cfg {String} navId The Roo.bootstrap.NavGroup which triggers show hide ()
13010 * Create a new TabPanel
13011 * @param {Object} config The config object
13014 Roo.bootstrap.TabPanel = function(config){
13015 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
13019 * Fires when the active status changes
13020 * @param {Roo.bootstrap.TabPanel} this
13021 * @param {Boolean} state the new state
13028 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
13035 getAutoCreate : function(){
13039 html: this.html || ''
13043 cfg.cls += ' active';
13047 cfg.tabId = this.tabId;
13052 onRender : function(ct, position)
13054 // Roo.log("Call onRender: " + this.xtype);
13056 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
13058 if (this.navId && this.tabId) {
13059 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
13061 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
13063 item.on('changed', function(item, state) {
13064 this.setActive(state);
13070 setActive: function(state)
13072 Roo.log("panel - set active " + this.tabId + "=" + state);
13074 this.active = state;
13076 this.el.removeClass('active');
13078 } else if (!this.el.hasClass('active')) {
13079 this.el.addClass('active');
13081 this.fireEvent('changed', this, state);
13098 * @class Roo.bootstrap.DateField
13099 * @extends Roo.bootstrap.Input
13100 * Bootstrap DateField class
13101 * @cfg {Number} weekStart default 0
13102 * @cfg {Number} weekStart default 0
13103 * @cfg {Number} viewMode default empty, (months|years)
13104 * @cfg {Number} minViewMode default empty, (months|years)
13105 * @cfg {Number} startDate default -Infinity
13106 * @cfg {Number} endDate default Infinity
13107 * @cfg {Boolean} todayHighlight default false
13108 * @cfg {Boolean} todayBtn default false
13109 * @cfg {Boolean} calendarWeeks default false
13110 * @cfg {Object} daysOfWeekDisabled default empty
13112 * @cfg {Boolean} keyboardNavigation default true
13113 * @cfg {String} language default en
13116 * Create a new DateField
13117 * @param {Object} config The config object
13120 Roo.bootstrap.DateField = function(config){
13121 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
13125 * Fires when this field show.
13126 * @param {Roo.bootstrap.DateField} this
13127 * @param {Mixed} date The date value
13132 * Fires when this field hide.
13133 * @param {Roo.bootstrap.DateField} this
13134 * @param {Mixed} date The date value
13139 * Fires when select a date.
13140 * @param {Roo.bootstrap.DateField} this
13141 * @param {Mixed} date The date value
13147 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
13150 * @cfg {String} format
13151 * The default date format string which can be overriden for localization support. The format must be
13152 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
13156 * @cfg {String} altFormats
13157 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
13158 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
13160 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
13168 todayHighlight : false,
13174 keyboardNavigation: true,
13176 calendarWeeks: false,
13178 startDate: -Infinity,
13182 daysOfWeekDisabled: [],
13186 UTCDate: function()
13188 return new Date(Date.UTC.apply(Date, arguments));
13191 UTCToday: function()
13193 var today = new Date();
13194 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
13197 getDate: function() {
13198 var d = this.getUTCDate();
13199 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
13202 getUTCDate: function() {
13206 setDate: function(d) {
13207 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
13210 setUTCDate: function(d) {
13212 this.setValue(this.formatDate(this.date));
13215 onRender: function(ct, position)
13218 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
13220 this.language = this.language || 'en';
13221 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
13222 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
13224 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
13225 this.format = this.format || 'm/d/y';
13226 this.isInline = false;
13227 this.isInput = true;
13228 this.component = this.el.select('.add-on', true).first() || false;
13229 this.component = (this.component && this.component.length === 0) ? false : this.component;
13230 this.hasInput = this.component && this.inputEL().length;
13232 if (typeof(this.minViewMode === 'string')) {
13233 switch (this.minViewMode) {
13235 this.minViewMode = 1;
13238 this.minViewMode = 2;
13241 this.minViewMode = 0;
13246 if (typeof(this.viewMode === 'string')) {
13247 switch (this.viewMode) {
13260 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
13262 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13264 this.picker().on('mousedown', this.onMousedown, this);
13265 this.picker().on('click', this.onClick, this);
13267 this.picker().addClass('datepicker-dropdown');
13269 this.startViewMode = this.viewMode;
13272 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
13273 if(!this.calendarWeeks){
13278 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
13279 v.attr('colspan', function(i, val){
13280 return parseInt(val) + 1;
13285 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
13287 this.setStartDate(this.startDate);
13288 this.setEndDate(this.endDate);
13290 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
13297 if(this.isInline) {
13302 picker : function()
13304 return this.el.select('.datepicker', true).first();
13307 fillDow: function()
13309 var dowCnt = this.weekStart;
13318 if(this.calendarWeeks){
13326 while (dowCnt < this.weekStart + 7) {
13330 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
13334 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
13337 fillMonths: function()
13340 var months = this.picker().select('>.datepicker-months td', true).first();
13342 months.dom.innerHTML = '';
13348 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
13351 months.createChild(month);
13356 update: function(){
13358 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
13360 if (this.date < this.startDate) {
13361 this.viewDate = new Date(this.startDate);
13362 } else if (this.date > this.endDate) {
13363 this.viewDate = new Date(this.endDate);
13365 this.viewDate = new Date(this.date);
13372 var d = new Date(this.viewDate),
13373 year = d.getUTCFullYear(),
13374 month = d.getUTCMonth(),
13375 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
13376 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
13377 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
13378 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
13379 currentDate = this.date && this.date.valueOf(),
13380 today = this.UTCToday();
13382 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
13384 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
13386 // this.picker.select('>tfoot th.today').
13387 // .text(dates[this.language].today)
13388 // .toggle(this.todayBtn !== false);
13390 this.updateNavArrows();
13393 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
13395 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
13397 prevMonth.setUTCDate(day);
13399 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
13401 var nextMonth = new Date(prevMonth);
13403 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
13405 nextMonth = nextMonth.valueOf();
13407 var fillMonths = false;
13409 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
13411 while(prevMonth.valueOf() < nextMonth) {
13414 if (prevMonth.getUTCDay() === this.weekStart) {
13416 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
13424 if(this.calendarWeeks){
13425 // ISO 8601: First week contains first thursday.
13426 // ISO also states week starts on Monday, but we can be more abstract here.
13428 // Start of current week: based on weekstart/current date
13429 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
13430 // Thursday of this week
13431 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
13432 // First Thursday of year, year from thursday
13433 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
13434 // Calendar week: ms between thursdays, div ms per day, div 7 days
13435 calWeek = (th - yth) / 864e5 / 7 + 1;
13437 fillMonths.cn.push({
13445 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
13447 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
13450 if (this.todayHighlight &&
13451 prevMonth.getUTCFullYear() == today.getFullYear() &&
13452 prevMonth.getUTCMonth() == today.getMonth() &&
13453 prevMonth.getUTCDate() == today.getDate()) {
13454 clsName += ' today';
13457 if (currentDate && prevMonth.valueOf() === currentDate) {
13458 clsName += ' active';
13461 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
13462 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
13463 clsName += ' disabled';
13466 fillMonths.cn.push({
13468 cls: 'day ' + clsName,
13469 html: prevMonth.getDate()
13472 prevMonth.setDate(prevMonth.getDate()+1);
13475 var currentYear = this.date && this.date.getUTCFullYear();
13476 var currentMonth = this.date && this.date.getUTCMonth();
13478 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
13480 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
13481 v.removeClass('active');
13483 if(currentYear === year && k === currentMonth){
13484 v.addClass('active');
13487 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
13488 v.addClass('disabled');
13494 year = parseInt(year/10, 10) * 10;
13496 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
13498 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
13501 for (var i = -1; i < 11; i++) {
13502 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
13504 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
13512 showMode: function(dir) {
13514 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
13516 Roo.each(this.picker().select('>div',true).elements, function(v){
13517 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13520 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
13525 if(this.isInline) return;
13527 this.picker().removeClass(['bottom', 'top']);
13529 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13531 * place to the top of element!
13535 this.picker().addClass('top');
13536 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13541 this.picker().addClass('bottom');
13543 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13546 parseDate : function(value){
13547 if(!value || value instanceof Date){
13550 var v = Date.parseDate(value, this.format);
13551 if (!v && this.useIso) {
13552 v = Date.parseDate(value, 'Y-m-d');
13554 if(!v && this.altFormats){
13555 if(!this.altFormatsArray){
13556 this.altFormatsArray = this.altFormats.split("|");
13558 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
13559 v = Date.parseDate(value, this.altFormatsArray[i]);
13565 formatDate : function(date, fmt){
13566 return (!date || !(date instanceof Date)) ?
13567 date : date.dateFormat(fmt || this.format);
13570 onFocus : function()
13572 Roo.bootstrap.DateField.superclass.onFocus.call(this);
13576 onBlur : function()
13578 Roo.bootstrap.DateField.superclass.onBlur.call(this);
13584 this.picker().show();
13588 this.fireEvent('show', this, this.date);
13593 if(this.isInline) return;
13594 this.picker().hide();
13595 this.viewMode = this.startViewMode;
13598 this.fireEvent('hide', this, this.date);
13602 onMousedown: function(e){
13603 e.stopPropagation();
13604 e.preventDefault();
13607 keyup: function(e){
13608 Roo.bootstrap.DateField.superclass.keyup.call(this);
13613 setValue: function(v){
13614 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
13616 this.fireEvent('select', this, this.date);
13620 fireKey: function(e){
13621 if (!this.picker().isVisible()){
13622 if (e.keyCode == 27) // allow escape to hide and re-show picker
13626 var dateChanged = false,
13628 newDate, newViewDate;
13632 e.preventDefault();
13636 if (!this.keyboardNavigation) break;
13637 dir = e.keyCode == 37 ? -1 : 1;
13640 newDate = this.moveYear(this.date, dir);
13641 newViewDate = this.moveYear(this.viewDate, dir);
13642 } else if (e.shiftKey){
13643 newDate = this.moveMonth(this.date, dir);
13644 newViewDate = this.moveMonth(this.viewDate, dir);
13646 newDate = new Date(this.date);
13647 newDate.setUTCDate(this.date.getUTCDate() + dir);
13648 newViewDate = new Date(this.viewDate);
13649 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
13651 if (this.dateWithinRange(newDate)){
13652 this.date = newDate;
13653 this.viewDate = newViewDate;
13654 this.setValue(this.formatDate(this.date));
13656 e.preventDefault();
13657 dateChanged = true;
13662 if (!this.keyboardNavigation) break;
13663 dir = e.keyCode == 38 ? -1 : 1;
13665 newDate = this.moveYear(this.date, dir);
13666 newViewDate = this.moveYear(this.viewDate, dir);
13667 } else if (e.shiftKey){
13668 newDate = this.moveMonth(this.date, dir);
13669 newViewDate = this.moveMonth(this.viewDate, dir);
13671 newDate = new Date(this.date);
13672 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
13673 newViewDate = new Date(this.viewDate);
13674 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
13676 if (this.dateWithinRange(newDate)){
13677 this.date = newDate;
13678 this.viewDate = newViewDate;
13679 this.setValue(this.formatDate(this.date));
13681 e.preventDefault();
13682 dateChanged = true;
13686 this.setValue(this.formatDate(this.date));
13688 e.preventDefault();
13691 this.setValue(this.formatDate(this.date));
13698 onClick: function(e) {
13699 e.stopPropagation();
13700 e.preventDefault();
13702 var target = e.getTarget();
13704 if(target.nodeName.toLowerCase() === 'i'){
13705 target = Roo.get(target).dom.parentNode;
13708 var nodeName = target.nodeName;
13709 var className = target.className;
13710 var html = target.innerHTML;
13712 switch(nodeName.toLowerCase()) {
13714 switch(className) {
13720 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
13721 switch(this.viewMode){
13723 this.viewDate = this.moveMonth(this.viewDate, dir);
13727 this.viewDate = this.moveYear(this.viewDate, dir);
13733 var date = new Date();
13734 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
13736 this.setValue(this.formatDate(this.date));
13742 if (className.indexOf('disabled') === -1) {
13743 this.viewDate.setUTCDate(1);
13744 if (className.indexOf('month') !== -1) {
13745 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
13747 var year = parseInt(html, 10) || 0;
13748 this.viewDate.setUTCFullYear(year);
13757 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
13758 var day = parseInt(html, 10) || 1;
13759 var year = this.viewDate.getUTCFullYear(),
13760 month = this.viewDate.getUTCMonth();
13762 if (className.indexOf('old') !== -1) {
13769 } else if (className.indexOf('new') !== -1) {
13777 this.date = this.UTCDate(year, month, day,0,0,0,0);
13778 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
13780 this.setValue(this.formatDate(this.date));
13787 setStartDate: function(startDate){
13788 this.startDate = startDate || -Infinity;
13789 if (this.startDate !== -Infinity) {
13790 this.startDate = this.parseDate(this.startDate);
13793 this.updateNavArrows();
13796 setEndDate: function(endDate){
13797 this.endDate = endDate || Infinity;
13798 if (this.endDate !== Infinity) {
13799 this.endDate = this.parseDate(this.endDate);
13802 this.updateNavArrows();
13805 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
13806 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
13807 if (typeof(this.daysOfWeekDisabled) !== 'object') {
13808 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
13810 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
13811 return parseInt(d, 10);
13814 this.updateNavArrows();
13817 updateNavArrows: function() {
13818 var d = new Date(this.viewDate),
13819 year = d.getUTCFullYear(),
13820 month = d.getUTCMonth();
13822 Roo.each(this.picker().select('.prev', true).elements, function(v){
13824 switch (this.viewMode) {
13827 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
13833 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13840 Roo.each(this.picker().select('.next', true).elements, function(v){
13842 switch (this.viewMode) {
13845 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13851 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13859 moveMonth: function(date, dir){
13860 if (!dir) return date;
13861 var new_date = new Date(date.valueOf()),
13862 day = new_date.getUTCDate(),
13863 month = new_date.getUTCMonth(),
13864 mag = Math.abs(dir),
13866 dir = dir > 0 ? 1 : -1;
13869 // If going back one month, make sure month is not current month
13870 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13872 return new_date.getUTCMonth() == month;
13874 // If going forward one month, make sure month is as expected
13875 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13877 return new_date.getUTCMonth() != new_month;
13879 new_month = month + dir;
13880 new_date.setUTCMonth(new_month);
13881 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13882 if (new_month < 0 || new_month > 11)
13883 new_month = (new_month + 12) % 12;
13885 // For magnitudes >1, move one month at a time...
13886 for (var i=0; i<mag; i++)
13887 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13888 new_date = this.moveMonth(new_date, dir);
13889 // ...then reset the day, keeping it in the new month
13890 new_month = new_date.getUTCMonth();
13891 new_date.setUTCDate(day);
13893 return new_month != new_date.getUTCMonth();
13896 // Common date-resetting loop -- if date is beyond end of month, make it
13899 new_date.setUTCDate(--day);
13900 new_date.setUTCMonth(new_month);
13905 moveYear: function(date, dir){
13906 return this.moveMonth(date, dir*12);
13909 dateWithinRange: function(date){
13910 return date >= this.startDate && date <= this.endDate;
13914 remove: function() {
13915 this.picker().remove();
13920 Roo.apply(Roo.bootstrap.DateField, {
13931 html: '<i class="fa fa-arrow-left"/>'
13941 html: '<i class="fa fa-arrow-right"/>'
13983 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13984 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13985 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13986 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13987 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
14000 navFnc: 'FullYear',
14005 navFnc: 'FullYear',
14010 Roo.apply(Roo.bootstrap.DateField, {
14014 cls: 'datepicker dropdown-menu',
14018 cls: 'datepicker-days',
14022 cls: 'table-condensed',
14024 Roo.bootstrap.DateField.head,
14028 Roo.bootstrap.DateField.footer
14035 cls: 'datepicker-months',
14039 cls: 'table-condensed',
14041 Roo.bootstrap.DateField.head,
14042 Roo.bootstrap.DateField.content,
14043 Roo.bootstrap.DateField.footer
14050 cls: 'datepicker-years',
14054 cls: 'table-condensed',
14056 Roo.bootstrap.DateField.head,
14057 Roo.bootstrap.DateField.content,
14058 Roo.bootstrap.DateField.footer
14077 * @class Roo.bootstrap.TimeField
14078 * @extends Roo.bootstrap.Input
14079 * Bootstrap DateField class
14083 * Create a new TimeField
14084 * @param {Object} config The config object
14087 Roo.bootstrap.TimeField = function(config){
14088 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
14092 * Fires when this field show.
14093 * @param {Roo.bootstrap.DateField} this
14094 * @param {Mixed} date The date value
14099 * Fires when this field hide.
14100 * @param {Roo.bootstrap.DateField} this
14101 * @param {Mixed} date The date value
14106 * Fires when select a date.
14107 * @param {Roo.bootstrap.DateField} this
14108 * @param {Mixed} date The date value
14114 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
14117 * @cfg {String} format
14118 * The default time format string which can be overriden for localization support. The format must be
14119 * valid according to {@link Date#parseDate} (defaults to 'H:i').
14123 onRender: function(ct, position)
14126 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
14128 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
14130 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
14132 this.pop = this.picker().select('>.datepicker-time',true).first();
14133 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
14135 this.picker().on('mousedown', this.onMousedown, this);
14136 this.picker().on('click', this.onClick, this);
14138 this.picker().addClass('datepicker-dropdown');
14143 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
14144 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
14145 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
14146 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
14147 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
14148 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
14152 fireKey: function(e){
14153 if (!this.picker().isVisible()){
14154 if (e.keyCode == 27) // allow escape to hide and re-show picker
14159 e.preventDefault();
14167 this.onTogglePeriod();
14170 this.onIncrementMinutes();
14173 this.onDecrementMinutes();
14182 onClick: function(e) {
14183 e.stopPropagation();
14184 e.preventDefault();
14187 picker : function()
14189 return this.el.select('.datepicker', true).first();
14192 fillTime: function()
14194 var time = this.pop.select('tbody', true).first();
14196 time.dom.innerHTML = '';
14211 cls: 'hours-up glyphicon glyphicon-chevron-up'
14231 cls: 'minutes-up glyphicon glyphicon-chevron-up'
14252 cls: 'timepicker-hour',
14267 cls: 'timepicker-minute',
14282 cls: 'btn btn-primary period',
14304 cls: 'hours-down glyphicon glyphicon-chevron-down'
14324 cls: 'minutes-down glyphicon glyphicon-chevron-down'
14342 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
14349 var hours = this.time.getHours();
14350 var minutes = this.time.getMinutes();
14363 hours = hours - 12;
14367 hours = '0' + hours;
14371 minutes = '0' + minutes;
14374 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
14375 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
14376 this.pop.select('button', true).first().dom.innerHTML = period;
14382 this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
14384 var cls = ['bottom'];
14386 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
14393 if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
14398 this.picker().addClass(cls.join('-'));
14402 Roo.each(cls, function(c){
14404 _this.picker().setTop(_this.inputEl().getHeight());
14408 _this.picker().setTop(0 - _this.picker().getHeight());
14413 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
14417 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
14424 onFocus : function()
14426 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
14430 onBlur : function()
14432 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
14438 this.picker().show();
14443 this.fireEvent('show', this, this.date);
14448 this.picker().hide();
14451 this.fireEvent('hide', this, this.date);
14454 setTime : function()
14457 this.setValue(this.time.format(this.format));
14459 this.fireEvent('select', this, this.date);
14464 onMousedown: function(e){
14465 e.stopPropagation();
14466 e.preventDefault();
14469 onIncrementHours: function()
14471 Roo.log('onIncrementHours');
14472 this.time = this.time.add(Date.HOUR, 1);
14477 onDecrementHours: function()
14479 Roo.log('onDecrementHours');
14480 this.time = this.time.add(Date.HOUR, -1);
14484 onIncrementMinutes: function()
14486 Roo.log('onIncrementMinutes');
14487 this.time = this.time.add(Date.MINUTE, 1);
14491 onDecrementMinutes: function()
14493 Roo.log('onDecrementMinutes');
14494 this.time = this.time.add(Date.MINUTE, -1);
14498 onTogglePeriod: function()
14500 Roo.log('onTogglePeriod');
14501 this.time = this.time.add(Date.HOUR, 12);
14508 Roo.apply(Roo.bootstrap.TimeField, {
14538 cls: 'btn btn-info ok',
14550 Roo.apply(Roo.bootstrap.TimeField, {
14554 cls: 'datepicker dropdown-menu',
14558 cls: 'datepicker-time',
14562 cls: 'table-condensed',
14564 Roo.bootstrap.TimeField.content,
14565 Roo.bootstrap.TimeField.footer
14584 * @class Roo.bootstrap.CheckBox
14585 * @extends Roo.bootstrap.Input
14586 * Bootstrap CheckBox class
14588 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
14589 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
14590 * @cfg {String} boxLabel The text that appears beside the checkbox
14591 * @cfg {String} weight (primary|warning|info|danger|success) The text that appears beside the checkbox
14592 * @cfg {Boolean} checked initnal the element
14596 * Create a new CheckBox
14597 * @param {Object} config The config object
14600 Roo.bootstrap.CheckBox = function(config){
14601 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
14606 * Fires when the element is checked or unchecked.
14607 * @param {Roo.bootstrap.CheckBox} this This input
14608 * @param {Boolean} checked The new checked value
14614 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
14616 inputType: 'checkbox',
14623 getAutoCreate : function()
14625 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14631 cfg.cls = 'form-group checkbox' //input-group
14639 type : this.inputType,
14640 value : (!this.checked) ? this.valueOff : this.inputValue,
14641 cls : 'roo-checkbox', //'form-box',
14642 placeholder : this.placeholder || ''
14646 if (this.weight) { // Validity check?
14647 cfg.cls += " checkbox-" + this.weight;
14650 if (this.disabled) {
14651 input.disabled=true;
14655 input.checked = this.checked;
14659 input.name = this.name;
14663 input.cls += ' input-' + this.size;
14667 ['xs','sm','md','lg'].map(function(size){
14668 if (settings[size]) {
14669 cfg.cls += ' col-' + size + '-' + settings[size];
14675 var inputblock = input;
14680 if (this.before || this.after) {
14683 cls : 'input-group',
14687 inputblock.cn.push({
14689 cls : 'input-group-addon',
14693 inputblock.cn.push(input);
14695 inputblock.cn.push({
14697 cls : 'input-group-addon',
14704 if (align ==='left' && this.fieldLabel.length) {
14705 Roo.log("left and has label");
14711 cls : 'control-label col-md-' + this.labelWidth,
14712 html : this.fieldLabel
14716 cls : "col-md-" + (12 - this.labelWidth),
14723 } else if ( this.fieldLabel.length) {
14728 tag: this.boxLabel ? 'span' : 'label',
14730 cls: 'control-label box-input-label',
14731 //cls : 'input-group-addon',
14732 html : this.fieldLabel
14742 Roo.log(" no label && no align");
14743 cfg.cn = [ inputblock ] ;
14752 html: this.boxLabel
14764 * return the real input element.
14766 inputEl: function ()
14768 return this.el.select('input.roo-checkbox',true).first();
14773 return this.el.select('label.control-label',true).first();
14776 initEvents : function()
14778 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
14780 this.inputEl().on('click', this.onClick, this);
14784 onClick : function()
14786 this.setChecked(!this.checked);
14789 setChecked : function(state,suppressEvent)
14791 this.checked = state;
14793 this.inputEl().dom.checked = state;
14795 if(suppressEvent !== true){
14796 this.fireEvent('check', this, state);
14799 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14803 setValue : function(v,suppressEvent)
14805 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
14819 * @class Roo.bootstrap.Radio
14820 * @extends Roo.bootstrap.CheckBox
14821 * Bootstrap Radio class
14824 * Create a new Radio
14825 * @param {Object} config The config object
14828 Roo.bootstrap.Radio = function(config){
14829 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
14833 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
14835 inputType: 'radio',
14839 getAutoCreate : function()
14841 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
14847 cfg.cls = 'form-group radio' //input-group
14852 type : this.inputType,
14853 value : (!this.checked) ? this.valueOff : this.inputValue,
14855 placeholder : this.placeholder || ''
14858 if (this.weight) { // Validity check?
14859 cfg.cls += " radio-" + this.weight;
14861 if (this.disabled) {
14862 input.disabled=true;
14866 input.checked = this.checked;
14870 input.name = this.name;
14874 input.cls += ' input-' + this.size;
14878 ['xs','sm','md','lg'].map(function(size){
14879 if (settings[size]) {
14880 cfg.cls += ' col-' + size + '-' + settings[size];
14884 var inputblock = input;
14886 if (this.before || this.after) {
14889 cls : 'input-group',
14893 inputblock.cn.push({
14895 cls : 'input-group-addon',
14899 inputblock.cn.push(input);
14901 inputblock.cn.push({
14903 cls : 'input-group-addon',
14910 if (align ==='left' && this.fieldLabel.length) {
14911 Roo.log("left and has label");
14917 cls : 'control-label col-md-' + this.labelWidth,
14918 html : this.fieldLabel
14922 cls : "col-md-" + (12 - this.labelWidth),
14929 } else if ( this.fieldLabel.length) {
14936 cls: 'control-label box-input-label',
14937 //cls : 'input-group-addon',
14938 html : this.fieldLabel
14948 Roo.log(" no label && no align");
14963 html: this.boxLabel
14970 inputEl: function ()
14972 return this.el.select('input.roo-radio',true).first();
14974 onClick : function()
14976 this.setChecked(true);
14979 setChecked : function(state,suppressEvent)
14982 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14983 v.dom.checked = false;
14987 this.checked = state;
14988 this.inputEl().dom.checked = state;
14990 if(suppressEvent !== true){
14991 this.fireEvent('check', this, state);
14994 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14998 getGroupValue : function()
15001 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
15002 if(v.dom.checked == true){
15003 value = v.dom.value;
15011 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
15012 * @return {Mixed} value The field value
15014 getValue : function(){
15015 return this.getGroupValue();
15021 //<script type="text/javascript">
15024 * Based Ext JS Library 1.1.1
15025 * Copyright(c) 2006-2007, Ext JS, LLC.
15031 * @class Roo.HtmlEditorCore
15032 * @extends Roo.Component
15033 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
15035 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
15038 Roo.HtmlEditorCore = function(config){
15041 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
15044 * @event initialize
15045 * Fires when the editor is fully initialized (including the iframe)
15046 * @param {Roo.HtmlEditorCore} this
15051 * Fires when the editor is first receives the focus. Any insertion must wait
15052 * until after this event.
15053 * @param {Roo.HtmlEditorCore} this
15057 * @event beforesync
15058 * Fires before the textarea is updated with content from the editor iframe. Return false
15059 * to cancel the sync.
15060 * @param {Roo.HtmlEditorCore} this
15061 * @param {String} html
15065 * @event beforepush
15066 * Fires before the iframe editor is updated with content from the textarea. Return false
15067 * to cancel the push.
15068 * @param {Roo.HtmlEditorCore} this
15069 * @param {String} html
15074 * Fires when the textarea is updated with content from the editor iframe.
15075 * @param {Roo.HtmlEditorCore} this
15076 * @param {String} html
15081 * Fires when the iframe editor is updated with content from the textarea.
15082 * @param {Roo.HtmlEditorCore} this
15083 * @param {String} html
15088 * @event editorevent
15089 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15090 * @param {Roo.HtmlEditorCore} this
15098 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
15102 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
15108 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15113 * @cfg {Number} height (in pixels)
15117 * @cfg {Number} width (in pixels)
15122 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15125 stylesheets: false,
15130 // private properties
15131 validationEvent : false,
15133 initialized : false,
15135 sourceEditMode : false,
15136 onFocus : Roo.emptyFn,
15138 hideMode:'offsets',
15146 * Protected method that will not generally be called directly. It
15147 * is called when the editor initializes the iframe with HTML contents. Override this method if you
15148 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
15150 getDocMarkup : function(){
15153 Roo.log(this.stylesheets);
15155 // inherit styels from page...??
15156 if (this.stylesheets === false) {
15158 Roo.get(document.head).select('style').each(function(node) {
15159 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15162 Roo.get(document.head).select('link').each(function(node) {
15163 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
15166 } else if (!this.stylesheets.length) {
15168 st = '<style type="text/css">' +
15169 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15172 Roo.each(this.stylesheets, function(s) {
15173 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
15178 st += '<style type="text/css">' +
15179 'IMG { cursor: pointer } ' +
15183 return '<html><head>' + st +
15184 //<style type="text/css">' +
15185 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
15187 ' </head><body class="roo-htmleditor-body"></body></html>';
15191 onRender : function(ct, position)
15194 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
15195 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
15198 this.el.dom.style.border = '0 none';
15199 this.el.dom.setAttribute('tabIndex', -1);
15200 this.el.addClass('x-hidden hide');
15204 if(Roo.isIE){ // fix IE 1px bogus margin
15205 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
15209 this.frameId = Roo.id();
15213 var iframe = this.owner.wrap.createChild({
15215 cls: 'form-control', // bootstrap..
15217 name: this.frameId,
15218 frameBorder : 'no',
15219 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
15224 this.iframe = iframe.dom;
15226 this.assignDocWin();
15228 this.doc.designMode = 'on';
15231 this.doc.write(this.getDocMarkup());
15235 var task = { // must defer to wait for browser to be ready
15237 //console.log("run task?" + this.doc.readyState);
15238 this.assignDocWin();
15239 if(this.doc.body || this.doc.readyState == 'complete'){
15241 this.doc.designMode="on";
15245 Roo.TaskMgr.stop(task);
15246 this.initEditor.defer(10, this);
15253 Roo.TaskMgr.start(task);
15260 onResize : function(w, h)
15262 Roo.log('resize: ' +w + ',' + h );
15263 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
15267 if(typeof w == 'number'){
15269 this.iframe.style.width = w + 'px';
15271 if(typeof h == 'number'){
15273 this.iframe.style.height = h + 'px';
15275 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
15282 * Toggles the editor between standard and source edit mode.
15283 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15285 toggleSourceEdit : function(sourceEditMode){
15287 this.sourceEditMode = sourceEditMode === true;
15289 if(this.sourceEditMode){
15291 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
15294 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
15295 //this.iframe.className = '';
15298 //this.setSize(this.owner.wrap.getSize());
15299 //this.fireEvent('editmodechange', this, this.sourceEditMode);
15306 * Protected method that will not generally be called directly. If you need/want
15307 * custom HTML cleanup, this is the method you should override.
15308 * @param {String} html The HTML to be cleaned
15309 * return {String} The cleaned HTML
15311 cleanHtml : function(html){
15312 html = String(html);
15313 if(html.length > 5){
15314 if(Roo.isSafari){ // strip safari nonsense
15315 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
15318 if(html == ' '){
15325 * HTML Editor -> Textarea
15326 * Protected method that will not generally be called directly. Syncs the contents
15327 * of the editor iframe with the textarea.
15329 syncValue : function(){
15330 if(this.initialized){
15331 var bd = (this.doc.body || this.doc.documentElement);
15332 //this.cleanUpPaste(); -- this is done else where and causes havoc..
15333 var html = bd.innerHTML;
15335 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
15336 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
15338 html = '<div style="'+m[0]+'">' + html + '</div>';
15341 html = this.cleanHtml(html);
15342 // fix up the special chars.. normaly like back quotes in word...
15343 // however we do not want to do this with chinese..
15344 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
15345 var cc = b.charCodeAt();
15347 (cc >= 0x4E00 && cc < 0xA000 ) ||
15348 (cc >= 0x3400 && cc < 0x4E00 ) ||
15349 (cc >= 0xf900 && cc < 0xfb00 )
15355 if(this.owner.fireEvent('beforesync', this, html) !== false){
15356 this.el.dom.value = html;
15357 this.owner.fireEvent('sync', this, html);
15363 * Protected method that will not generally be called directly. Pushes the value of the textarea
15364 * into the iframe editor.
15366 pushValue : function(){
15367 if(this.initialized){
15368 var v = this.el.dom.value.trim();
15370 // if(v.length < 1){
15374 if(this.owner.fireEvent('beforepush', this, v) !== false){
15375 var d = (this.doc.body || this.doc.documentElement);
15377 this.cleanUpPaste();
15378 this.el.dom.value = d.innerHTML;
15379 this.owner.fireEvent('push', this, v);
15385 deferFocus : function(){
15386 this.focus.defer(10, this);
15390 focus : function(){
15391 if(this.win && !this.sourceEditMode){
15398 assignDocWin: function()
15400 var iframe = this.iframe;
15403 this.doc = iframe.contentWindow.document;
15404 this.win = iframe.contentWindow;
15406 if (!Roo.get(this.frameId)) {
15409 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
15410 this.win = Roo.get(this.frameId).dom.contentWindow;
15415 initEditor : function(){
15416 //console.log("INIT EDITOR");
15417 this.assignDocWin();
15421 this.doc.designMode="on";
15423 this.doc.write(this.getDocMarkup());
15426 var dbody = (this.doc.body || this.doc.documentElement);
15427 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
15428 // this copies styles from the containing element into thsi one..
15429 // not sure why we need all of this..
15430 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
15432 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
15433 //ss['background-attachment'] = 'fixed'; // w3c
15434 dbody.bgProperties = 'fixed'; // ie
15435 //Roo.DomHelper.applyStyles(dbody, ss);
15436 Roo.EventManager.on(this.doc, {
15437 //'mousedown': this.onEditorEvent,
15438 'mouseup': this.onEditorEvent,
15439 'dblclick': this.onEditorEvent,
15440 'click': this.onEditorEvent,
15441 'keyup': this.onEditorEvent,
15446 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
15448 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
15449 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
15451 this.initialized = true;
15453 this.owner.fireEvent('initialize', this);
15458 onDestroy : function(){
15464 //for (var i =0; i < this.toolbars.length;i++) {
15465 // // fixme - ask toolbars for heights?
15466 // this.toolbars[i].onDestroy();
15469 //this.wrap.dom.innerHTML = '';
15470 //this.wrap.remove();
15475 onFirstFocus : function(){
15477 this.assignDocWin();
15480 this.activated = true;
15483 if(Roo.isGecko){ // prevent silly gecko errors
15485 var s = this.win.getSelection();
15486 if(!s.focusNode || s.focusNode.nodeType != 3){
15487 var r = s.getRangeAt(0);
15488 r.selectNodeContents((this.doc.body || this.doc.documentElement));
15493 this.execCmd('useCSS', true);
15494 this.execCmd('styleWithCSS', false);
15497 this.owner.fireEvent('activate', this);
15501 adjustFont: function(btn){
15502 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
15503 //if(Roo.isSafari){ // safari
15506 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
15507 if(Roo.isSafari){ // safari
15508 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
15509 v = (v < 10) ? 10 : v;
15510 v = (v > 48) ? 48 : v;
15511 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
15516 v = Math.max(1, v+adjust);
15518 this.execCmd('FontSize', v );
15521 onEditorEvent : function(e){
15522 this.owner.fireEvent('editorevent', this, e);
15523 // this.updateToolbar();
15524 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
15527 insertTag : function(tg)
15529 // could be a bit smarter... -> wrap the current selected tRoo..
15530 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
15532 range = this.createRange(this.getSelection());
15533 var wrappingNode = this.doc.createElement(tg.toLowerCase());
15534 wrappingNode.appendChild(range.extractContents());
15535 range.insertNode(wrappingNode);
15542 this.execCmd("formatblock", tg);
15546 insertText : function(txt)
15550 var range = this.createRange();
15551 range.deleteContents();
15552 //alert(Sender.getAttribute('label'));
15554 range.insertNode(this.doc.createTextNode(txt));
15560 * Executes a Midas editor command on the editor document and performs necessary focus and
15561 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
15562 * @param {String} cmd The Midas command
15563 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15565 relayCmd : function(cmd, value){
15567 this.execCmd(cmd, value);
15568 this.owner.fireEvent('editorevent', this);
15569 //this.updateToolbar();
15570 this.owner.deferFocus();
15574 * Executes a Midas editor command directly on the editor document.
15575 * For visual commands, you should use {@link #relayCmd} instead.
15576 * <b>This should only be called after the editor is initialized.</b>
15577 * @param {String} cmd The Midas command
15578 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
15580 execCmd : function(cmd, value){
15581 this.doc.execCommand(cmd, false, value === undefined ? null : value);
15588 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
15590 * @param {String} text | dom node..
15592 insertAtCursor : function(text)
15597 if(!this.activated){
15603 var r = this.doc.selection.createRange();
15614 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
15618 // from jquery ui (MIT licenced)
15620 var win = this.win;
15622 if (win.getSelection && win.getSelection().getRangeAt) {
15623 range = win.getSelection().getRangeAt(0);
15624 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
15625 range.insertNode(node);
15626 } else if (win.document.selection && win.document.selection.createRange) {
15627 // no firefox support
15628 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15629 win.document.selection.createRange().pasteHTML(txt);
15631 // no firefox support
15632 var txt = typeof(text) == 'string' ? text : text.outerHTML;
15633 this.execCmd('InsertHTML', txt);
15642 mozKeyPress : function(e){
15644 var c = e.getCharCode(), cmd;
15647 c = String.fromCharCode(c).toLowerCase();
15661 this.cleanUpPaste.defer(100, this);
15669 e.preventDefault();
15677 fixKeys : function(){ // load time branching for fastest keydown performance
15679 return function(e){
15680 var k = e.getKey(), r;
15683 r = this.doc.selection.createRange();
15686 r.pasteHTML('    ');
15693 r = this.doc.selection.createRange();
15695 var target = r.parentElement();
15696 if(!target || target.tagName.toLowerCase() != 'li'){
15698 r.pasteHTML('<br />');
15704 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15705 this.cleanUpPaste.defer(100, this);
15711 }else if(Roo.isOpera){
15712 return function(e){
15713 var k = e.getKey();
15717 this.execCmd('InsertHTML','    ');
15720 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15721 this.cleanUpPaste.defer(100, this);
15726 }else if(Roo.isSafari){
15727 return function(e){
15728 var k = e.getKey();
15732 this.execCmd('InsertText','\t');
15736 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
15737 this.cleanUpPaste.defer(100, this);
15745 getAllAncestors: function()
15747 var p = this.getSelectedNode();
15750 a.push(p); // push blank onto stack..
15751 p = this.getParentElement();
15755 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
15759 a.push(this.doc.body);
15763 lastSelNode : false,
15766 getSelection : function()
15768 this.assignDocWin();
15769 return Roo.isIE ? this.doc.selection : this.win.getSelection();
15772 getSelectedNode: function()
15774 // this may only work on Gecko!!!
15776 // should we cache this!!!!
15781 var range = this.createRange(this.getSelection()).cloneRange();
15784 var parent = range.parentElement();
15786 var testRange = range.duplicate();
15787 testRange.moveToElementText(parent);
15788 if (testRange.inRange(range)) {
15791 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
15794 parent = parent.parentElement;
15799 // is ancestor a text element.
15800 var ac = range.commonAncestorContainer;
15801 if (ac.nodeType == 3) {
15802 ac = ac.parentNode;
15805 var ar = ac.childNodes;
15808 var other_nodes = [];
15809 var has_other_nodes = false;
15810 for (var i=0;i<ar.length;i++) {
15811 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
15814 // fullly contained node.
15816 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
15821 // probably selected..
15822 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
15823 other_nodes.push(ar[i]);
15827 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
15832 has_other_nodes = true;
15834 if (!nodes.length && other_nodes.length) {
15835 nodes= other_nodes;
15837 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
15843 createRange: function(sel)
15845 // this has strange effects when using with
15846 // top toolbar - not sure if it's a great idea.
15847 //this.editor.contentWindow.focus();
15848 if (typeof sel != "undefined") {
15850 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
15852 return this.doc.createRange();
15855 return this.doc.createRange();
15858 getParentElement: function()
15861 this.assignDocWin();
15862 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
15864 var range = this.createRange(sel);
15867 var p = range.commonAncestorContainer;
15868 while (p.nodeType == 3) { // text node
15879 * Range intersection.. the hard stuff...
15883 * [ -- selected range --- ]
15887 * if end is before start or hits it. fail.
15888 * if start is after end or hits it fail.
15890 * if either hits (but other is outside. - then it's not
15896 // @see http://www.thismuchiknow.co.uk/?p=64.
15897 rangeIntersectsNode : function(range, node)
15899 var nodeRange = node.ownerDocument.createRange();
15901 nodeRange.selectNode(node);
15903 nodeRange.selectNodeContents(node);
15906 var rangeStartRange = range.cloneRange();
15907 rangeStartRange.collapse(true);
15909 var rangeEndRange = range.cloneRange();
15910 rangeEndRange.collapse(false);
15912 var nodeStartRange = nodeRange.cloneRange();
15913 nodeStartRange.collapse(true);
15915 var nodeEndRange = nodeRange.cloneRange();
15916 nodeEndRange.collapse(false);
15918 return rangeStartRange.compareBoundaryPoints(
15919 Range.START_TO_START, nodeEndRange) == -1 &&
15920 rangeEndRange.compareBoundaryPoints(
15921 Range.START_TO_START, nodeStartRange) == 1;
15925 rangeCompareNode : function(range, node)
15927 var nodeRange = node.ownerDocument.createRange();
15929 nodeRange.selectNode(node);
15931 nodeRange.selectNodeContents(node);
15935 range.collapse(true);
15937 nodeRange.collapse(true);
15939 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15940 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15942 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15944 var nodeIsBefore = ss == 1;
15945 var nodeIsAfter = ee == -1;
15947 if (nodeIsBefore && nodeIsAfter)
15949 if (!nodeIsBefore && nodeIsAfter)
15950 return 1; //right trailed.
15952 if (nodeIsBefore && !nodeIsAfter)
15953 return 2; // left trailed.
15958 // private? - in a new class?
15959 cleanUpPaste : function()
15961 // cleans up the whole document..
15962 Roo.log('cleanuppaste');
15964 this.cleanUpChildren(this.doc.body);
15965 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15966 if (clean != this.doc.body.innerHTML) {
15967 this.doc.body.innerHTML = clean;
15972 cleanWordChars : function(input) {// change the chars to hex code
15973 var he = Roo.HtmlEditorCore;
15975 var output = input;
15976 Roo.each(he.swapCodes, function(sw) {
15977 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15979 output = output.replace(swapper, sw[1]);
15986 cleanUpChildren : function (n)
15988 if (!n.childNodes.length) {
15991 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15992 this.cleanUpChild(n.childNodes[i]);
15999 cleanUpChild : function (node)
16002 //console.log(node);
16003 if (node.nodeName == "#text") {
16004 // clean up silly Windows -- stuff?
16007 if (node.nodeName == "#comment") {
16008 node.parentNode.removeChild(node);
16009 // clean up silly Windows -- stuff?
16013 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
16015 node.parentNode.removeChild(node);
16020 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
16022 // remove <a name=....> as rendering on yahoo mailer is borked with this.
16023 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
16025 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
16026 // remove_keep_children = true;
16029 if (remove_keep_children) {
16030 this.cleanUpChildren(node);
16031 // inserts everything just before this node...
16032 while (node.childNodes.length) {
16033 var cn = node.childNodes[0];
16034 node.removeChild(cn);
16035 node.parentNode.insertBefore(cn, node);
16037 node.parentNode.removeChild(node);
16041 if (!node.attributes || !node.attributes.length) {
16042 this.cleanUpChildren(node);
16046 function cleanAttr(n,v)
16049 if (v.match(/^\./) || v.match(/^\//)) {
16052 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
16055 if (v.match(/^#/)) {
16058 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
16059 node.removeAttribute(n);
16063 function cleanStyle(n,v)
16065 if (v.match(/expression/)) { //XSS?? should we even bother..
16066 node.removeAttribute(n);
16069 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
16070 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
16073 var parts = v.split(/;/);
16076 Roo.each(parts, function(p) {
16077 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
16081 var l = p.split(':').shift().replace(/\s+/g,'');
16082 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
16084 if ( cblack.indexOf(l) > -1) {
16085 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16086 //node.removeAttribute(n);
16090 // only allow 'c whitelisted system attributes'
16091 if ( cwhite.length && cwhite.indexOf(l) < 0) {
16092 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
16093 //node.removeAttribute(n);
16103 if (clean.length) {
16104 node.setAttribute(n, clean.join(';'));
16106 node.removeAttribute(n);
16112 for (var i = node.attributes.length-1; i > -1 ; i--) {
16113 var a = node.attributes[i];
16116 if (a.name.toLowerCase().substr(0,2)=='on') {
16117 node.removeAttribute(a.name);
16120 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
16121 node.removeAttribute(a.name);
16124 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
16125 cleanAttr(a.name,a.value); // fixme..
16128 if (a.name == 'style') {
16129 cleanStyle(a.name,a.value);
16132 /// clean up MS crap..
16133 // tecnically this should be a list of valid class'es..
16136 if (a.name == 'class') {
16137 if (a.value.match(/^Mso/)) {
16138 node.className = '';
16141 if (a.value.match(/body/)) {
16142 node.className = '';
16153 this.cleanUpChildren(node);
16158 * Clean up MS wordisms...
16160 cleanWord : function(node)
16163 var cleanWordChildren = function()
16165 if (!node.childNodes.length) {
16168 for (var i = node.childNodes.length-1; i > -1 ; i--) {
16169 _t.cleanWord(node.childNodes[i]);
16175 this.cleanWord(this.doc.body);
16178 if (node.nodeName == "#text") {
16179 // clean up silly Windows -- stuff?
16182 if (node.nodeName == "#comment") {
16183 node.parentNode.removeChild(node);
16184 // clean up silly Windows -- stuff?
16188 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
16189 node.parentNode.removeChild(node);
16193 // remove - but keep children..
16194 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
16195 while (node.childNodes.length) {
16196 var cn = node.childNodes[0];
16197 node.removeChild(cn);
16198 node.parentNode.insertBefore(cn, node);
16200 node.parentNode.removeChild(node);
16201 cleanWordChildren();
16205 if (node.className.length) {
16207 var cn = node.className.split(/\W+/);
16209 Roo.each(cn, function(cls) {
16210 if (cls.match(/Mso[a-zA-Z]+/)) {
16215 node.className = cna.length ? cna.join(' ') : '';
16217 node.removeAttribute("class");
16221 if (node.hasAttribute("lang")) {
16222 node.removeAttribute("lang");
16225 if (node.hasAttribute("style")) {
16227 var styles = node.getAttribute("style").split(";");
16229 Roo.each(styles, function(s) {
16230 if (!s.match(/:/)) {
16233 var kv = s.split(":");
16234 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
16237 // what ever is left... we allow.
16240 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
16241 if (!nstyle.length) {
16242 node.removeAttribute('style');
16246 cleanWordChildren();
16250 domToHTML : function(currentElement, depth, nopadtext) {
16252 depth = depth || 0;
16253 nopadtext = nopadtext || false;
16255 if (!currentElement) {
16256 return this.domToHTML(this.doc.body);
16259 //Roo.log(currentElement);
16261 var allText = false;
16262 var nodeName = currentElement.nodeName;
16263 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
16265 if (nodeName == '#text') {
16266 return currentElement.nodeValue;
16271 if (nodeName != 'BODY') {
16274 // Prints the node tagName, such as <A>, <IMG>, etc
16277 for(i = 0; i < currentElement.attributes.length;i++) {
16279 var aname = currentElement.attributes.item(i).name;
16280 if (!currentElement.attributes.item(i).value.length) {
16283 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
16286 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
16295 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
16298 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
16303 // Traverse the tree
16305 var currentElementChild = currentElement.childNodes.item(i);
16306 var allText = true;
16307 var innerHTML = '';
16309 while (currentElementChild) {
16310 // Formatting code (indent the tree so it looks nice on the screen)
16311 var nopad = nopadtext;
16312 if (lastnode == 'SPAN') {
16316 if (currentElementChild.nodeName == '#text') {
16317 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
16318 if (!nopad && toadd.length > 80) {
16319 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
16321 innerHTML += toadd;
16324 currentElementChild = currentElement.childNodes.item(i);
16330 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
16332 // Recursively traverse the tree structure of the child node
16333 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
16334 lastnode = currentElementChild.nodeName;
16336 currentElementChild=currentElement.childNodes.item(i);
16342 // The remaining code is mostly for formatting the tree
16343 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
16348 ret+= "</"+tagName+">";
16354 // hide stuff that is not compatible
16368 * @event specialkey
16372 * @cfg {String} fieldClass @hide
16375 * @cfg {String} focusClass @hide
16378 * @cfg {String} autoCreate @hide
16381 * @cfg {String} inputType @hide
16384 * @cfg {String} invalidClass @hide
16387 * @cfg {String} invalidText @hide
16390 * @cfg {String} msgFx @hide
16393 * @cfg {String} validateOnBlur @hide
16397 Roo.HtmlEditorCore.white = [
16398 'area', 'br', 'img', 'input', 'hr', 'wbr',
16400 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
16401 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
16402 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
16403 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
16404 'table', 'ul', 'xmp',
16406 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
16409 'dir', 'menu', 'ol', 'ul', 'dl',
16415 Roo.HtmlEditorCore.black = [
16416 // 'embed', 'object', // enable - backend responsiblity to clean thiese
16418 'base', 'basefont', 'bgsound', 'blink', 'body',
16419 'frame', 'frameset', 'head', 'html', 'ilayer',
16420 'iframe', 'layer', 'link', 'meta', 'object',
16421 'script', 'style' ,'title', 'xml' // clean later..
16423 Roo.HtmlEditorCore.clean = [
16424 'script', 'style', 'title', 'xml'
16426 Roo.HtmlEditorCore.remove = [
16431 Roo.HtmlEditorCore.ablack = [
16435 Roo.HtmlEditorCore.aclean = [
16436 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
16440 Roo.HtmlEditorCore.pwhite= [
16441 'http', 'https', 'mailto'
16444 // white listed style attributes.
16445 Roo.HtmlEditorCore.cwhite= [
16446 // 'text-align', /// default is to allow most things..
16452 // black listed style attributes.
16453 Roo.HtmlEditorCore.cblack= [
16454 // 'font-size' -- this can be set by the project
16458 Roo.HtmlEditorCore.swapCodes =[
16477 * @class Roo.bootstrap.HtmlEditor
16478 * @extends Roo.bootstrap.TextArea
16479 * Bootstrap HtmlEditor class
16482 * Create a new HtmlEditor
16483 * @param {Object} config The config object
16486 Roo.bootstrap.HtmlEditor = function(config){
16487 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
16488 if (!this.toolbars) {
16489 this.toolbars = [];
16491 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
16494 * @event initialize
16495 * Fires when the editor is fully initialized (including the iframe)
16496 * @param {HtmlEditor} this
16501 * Fires when the editor is first receives the focus. Any insertion must wait
16502 * until after this event.
16503 * @param {HtmlEditor} this
16507 * @event beforesync
16508 * Fires before the textarea is updated with content from the editor iframe. Return false
16509 * to cancel the sync.
16510 * @param {HtmlEditor} this
16511 * @param {String} html
16515 * @event beforepush
16516 * Fires before the iframe editor is updated with content from the textarea. Return false
16517 * to cancel the push.
16518 * @param {HtmlEditor} this
16519 * @param {String} html
16524 * Fires when the textarea is updated with content from the editor iframe.
16525 * @param {HtmlEditor} this
16526 * @param {String} html
16531 * Fires when the iframe editor is updated with content from the textarea.
16532 * @param {HtmlEditor} this
16533 * @param {String} html
16537 * @event editmodechange
16538 * Fires when the editor switches edit modes
16539 * @param {HtmlEditor} this
16540 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
16542 editmodechange: true,
16544 * @event editorevent
16545 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
16546 * @param {HtmlEditor} this
16550 * @event firstfocus
16551 * Fires when on first focus - needed by toolbars..
16552 * @param {HtmlEditor} this
16557 * Auto save the htmlEditor value as a file into Events
16558 * @param {HtmlEditor} this
16562 * @event savedpreview
16563 * preview the saved version of htmlEditor
16564 * @param {HtmlEditor} this
16571 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
16575 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
16580 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
16585 * @cfg {Number} height (in pixels)
16589 * @cfg {Number} width (in pixels)
16594 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
16597 stylesheets: false,
16602 // private properties
16603 validationEvent : false,
16605 initialized : false,
16608 onFocus : Roo.emptyFn,
16610 hideMode:'offsets',
16613 tbContainer : false,
16615 toolbarContainer :function() {
16616 return this.wrap.select('.x-html-editor-tb',true).first();
16620 * Protected method that will not generally be called directly. It
16621 * is called when the editor creates its toolbar. Override this method if you need to
16622 * add custom toolbar buttons.
16623 * @param {HtmlEditor} editor
16625 createToolbar : function(){
16627 Roo.log("create toolbars");
16629 this.toolbars = [ new Roo.bootstrap.htmleditor.ToolbarStandard({editor: this} ) ];
16630 this.toolbars[0].render(this.toolbarContainer());
16634 // if (!editor.toolbars || !editor.toolbars.length) {
16635 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
16638 // for (var i =0 ; i < editor.toolbars.length;i++) {
16639 // editor.toolbars[i] = Roo.factory(
16640 // typeof(editor.toolbars[i]) == 'string' ?
16641 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
16642 // Roo.bootstrap.HtmlEditor);
16643 // editor.toolbars[i].init(editor);
16649 onRender : function(ct, position)
16651 // Roo.log("Call onRender: " + this.xtype);
16653 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
16655 this.wrap = this.inputEl().wrap({
16656 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
16659 this.editorcore.onRender(ct, position);
16661 if (this.resizable) {
16662 this.resizeEl = new Roo.Resizable(this.wrap, {
16666 minHeight : this.height,
16667 height: this.height,
16668 handles : this.resizable,
16671 resize : function(r, w, h) {
16672 _t.onResize(w,h); // -something
16678 this.createToolbar(this);
16681 if(!this.width && this.resizable){
16682 this.setSize(this.wrap.getSize());
16684 if (this.resizeEl) {
16685 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
16686 // should trigger onReize..
16692 onResize : function(w, h)
16694 Roo.log('resize: ' +w + ',' + h );
16695 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
16699 if(this.inputEl() ){
16700 if(typeof w == 'number'){
16701 var aw = w - this.wrap.getFrameWidth('lr');
16702 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
16705 if(typeof h == 'number'){
16706 var tbh = -11; // fixme it needs to tool bar size!
16707 for (var i =0; i < this.toolbars.length;i++) {
16708 // fixme - ask toolbars for heights?
16709 tbh += this.toolbars[i].el.getHeight();
16710 //if (this.toolbars[i].footer) {
16711 // tbh += this.toolbars[i].footer.el.getHeight();
16719 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
16720 ah -= 5; // knock a few pixes off for look..
16721 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
16725 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
16726 this.editorcore.onResize(ew,eh);
16731 * Toggles the editor between standard and source edit mode.
16732 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
16734 toggleSourceEdit : function(sourceEditMode)
16736 this.editorcore.toggleSourceEdit(sourceEditMode);
16738 if(this.editorcore.sourceEditMode){
16739 Roo.log('editor - showing textarea');
16742 // Roo.log(this.syncValue());
16744 this.inputEl().removeClass('hide');
16745 this.inputEl().dom.removeAttribute('tabIndex');
16746 this.inputEl().focus();
16748 Roo.log('editor - hiding textarea');
16750 // Roo.log(this.pushValue());
16753 this.inputEl().addClass('hide');
16754 this.inputEl().dom.setAttribute('tabIndex', -1);
16755 //this.deferFocus();
16758 if(this.resizable){
16759 this.setSize(this.wrap.getSize());
16762 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
16765 // private (for BoxComponent)
16766 adjustSize : Roo.BoxComponent.prototype.adjustSize,
16768 // private (for BoxComponent)
16769 getResizeEl : function(){
16773 // private (for BoxComponent)
16774 getPositionEl : function(){
16779 initEvents : function(){
16780 this.originalValue = this.getValue();
16784 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16787 // markInvalid : Roo.emptyFn,
16789 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
16792 // clearInvalid : Roo.emptyFn,
16794 setValue : function(v){
16795 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
16796 this.editorcore.pushValue();
16801 deferFocus : function(){
16802 this.focus.defer(10, this);
16806 focus : function(){
16807 this.editorcore.focus();
16813 onDestroy : function(){
16819 for (var i =0; i < this.toolbars.length;i++) {
16820 // fixme - ask toolbars for heights?
16821 this.toolbars[i].onDestroy();
16824 this.wrap.dom.innerHTML = '';
16825 this.wrap.remove();
16830 onFirstFocus : function(){
16831 //Roo.log("onFirstFocus");
16832 this.editorcore.onFirstFocus();
16833 for (var i =0; i < this.toolbars.length;i++) {
16834 this.toolbars[i].onFirstFocus();
16840 syncValue : function()
16842 this.editorcore.syncValue();
16845 pushValue : function()
16847 this.editorcore.pushValue();
16851 // hide stuff that is not compatible
16865 * @event specialkey
16869 * @cfg {String} fieldClass @hide
16872 * @cfg {String} focusClass @hide
16875 * @cfg {String} autoCreate @hide
16878 * @cfg {String} inputType @hide
16881 * @cfg {String} invalidClass @hide
16884 * @cfg {String} invalidText @hide
16887 * @cfg {String} msgFx @hide
16890 * @cfg {String} validateOnBlur @hide
16899 Roo.namespace('Roo.bootstrap.htmleditor');
16901 * @class Roo.bootstrap.HtmlEditorToolbar1
16906 new Roo.bootstrap.HtmlEditor({
16909 new Roo.bootstrap.HtmlEditorToolbar1({
16910 disable : { fonts: 1 , format: 1, ..., ... , ...],
16916 * @cfg {Object} disable List of elements to disable..
16917 * @cfg {Array} btns List of additional buttons.
16921 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
16924 Roo.bootstrap.htmleditor.ToolbarStandard = function(config)
16927 Roo.apply(this, config);
16929 // default disabled, based on 'good practice'..
16930 this.disable = this.disable || {};
16931 Roo.applyIf(this.disable, {
16934 specialElements : true
16936 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.constructor.call(this, config);
16938 this.editor = config.editor;
16939 this.editorcore = config.editor.editorcore;
16941 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
16943 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
16944 // dont call parent... till later.
16946 Roo.extend(Roo.bootstrap.htmleditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
16951 editorcore : false,
16956 "h1","h2","h3","h4","h5","h6",
16958 "abbr", "acronym", "address", "cite", "samp", "var",
16962 onRender : function(ct, position)
16964 // Roo.log("Call onRender: " + this.xtype);
16966 Roo.bootstrap.htmleditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
16968 this.el.dom.style.marginBottom = '0';
16970 var editorcore = this.editorcore;
16971 var editor= this.editor;
16974 var btn = function(id,cmd , toggle, handler){
16976 var event = toggle ? 'toggle' : 'click';
16981 xns: Roo.bootstrap,
16984 enableToggle:toggle !== false,
16986 pressed : toggle ? false : null,
16989 a.listeners[toggle ? 'toggle' : 'click'] = function() {
16990 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
16999 xns: Roo.bootstrap,
17000 glyphicon : 'font',
17004 xns: Roo.bootstrap,
17008 Roo.each(this.formats, function(f) {
17009 style.menu.items.push({
17011 xns: Roo.bootstrap,
17012 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
17017 editorcore.insertTag(this.tagname);
17024 children.push(style);
17027 btn('bold',false,true);
17028 btn('italic',false,true);
17029 btn('align-left', 'justifyleft',true);
17030 btn('align-center', 'justifycenter',true);
17031 btn('align-right' , 'justifyright',true);
17032 btn('link', false, false, function(btn) {
17033 //Roo.log("create link?");
17034 var url = prompt(this.createLinkText, this.defaultLinkValue);
17035 if(url && url != 'http:/'+'/'){
17036 this.editorcore.relayCmd('createlink', url);
17039 btn('list','insertunorderedlist',true);
17040 btn('pencil', false,true, function(btn){
17043 this.toggleSourceEdit(btn.pressed);
17049 xns: Roo.bootstrap,
17054 xns: Roo.bootstrap,
17059 cog.menu.items.push({
17061 xns: Roo.bootstrap,
17062 html : Clean styles,
17067 editorcore.insertTag(this.tagname);
17076 this.xtype = 'NavSimplebar';
17078 for(var i=0;i< children.length;i++) {
17080 this.buttons.add(this.addxtypeChild(children[i]));
17084 editor.on('editorevent', this.updateToolbar, this);
17086 onBtnClick : function(id)
17088 this.editorcore.relayCmd(id);
17089 this.editorcore.focus();
17093 * Protected method that will not generally be called directly. It triggers
17094 * a toolbar update by reading the markup state of the current selection in the editor.
17096 updateToolbar: function(){
17098 if(!this.editorcore.activated){
17099 this.editor.onFirstFocus(); // is this neeed?
17103 var btns = this.buttons;
17104 var doc = this.editorcore.doc;
17105 btns.get('bold').setActive(doc.queryCommandState('bold'));
17106 btns.get('italic').setActive(doc.queryCommandState('italic'));
17107 //btns.get('underline').setActive(doc.queryCommandState('underline'));
17109 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
17110 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
17111 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
17113 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
17114 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
17117 var ans = this.editorcore.getAllAncestors();
17118 if (this.formatCombo) {
17121 var store = this.formatCombo.store;
17122 this.formatCombo.setValue("");
17123 for (var i =0; i < ans.length;i++) {
17124 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
17126 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
17134 // hides menus... - so this cant be on a menu...
17135 Roo.bootstrap.MenuMgr.hideAll();
17137 Roo.bootstrap.MenuMgr.hideAll();
17138 //this.editorsyncValue();
17140 onFirstFocus: function() {
17141 this.buttons.each(function(item){
17145 toggleSourceEdit : function(sourceEditMode){
17148 if(sourceEditMode){
17149 Roo.log("disabling buttons");
17150 this.buttons.each( function(item){
17151 if(item.cmd != 'pencil'){
17157 Roo.log("enabling buttons");
17158 if(this.editorcore.initialized){
17159 this.buttons.each( function(item){
17165 Roo.log("calling toggole on editor");
17166 // tell the editor that it's been pressed..
17167 this.editor.toggleSourceEdit(sourceEditMode);
17177 * @class Roo.bootstrap.Table.AbstractSelectionModel
17178 * @extends Roo.util.Observable
17179 * Abstract base class for grid SelectionModels. It provides the interface that should be
17180 * implemented by descendant classes. This class should not be directly instantiated.
17183 Roo.bootstrap.Table.AbstractSelectionModel = function(){
17184 this.locked = false;
17185 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
17189 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
17190 /** @ignore Called by the grid automatically. Do not call directly. */
17191 init : function(grid){
17197 * Locks the selections.
17200 this.locked = true;
17204 * Unlocks the selections.
17206 unlock : function(){
17207 this.locked = false;
17211 * Returns true if the selections are locked.
17212 * @return {Boolean}
17214 isLocked : function(){
17215 return this.locked;
17219 * @extends Roo.bootstrap.Table.AbstractSelectionModel
17220 * @class Roo.bootstrap.Table.RowSelectionModel
17221 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
17222 * It supports multiple selections and keyboard selection/navigation.
17224 * @param {Object} config
17227 Roo.bootstrap.Table.RowSelectionModel = function(config){
17228 Roo.apply(this, config);
17229 this.selections = new Roo.util.MixedCollection(false, function(o){
17234 this.lastActive = false;
17238 * @event selectionchange
17239 * Fires when the selection changes
17240 * @param {SelectionModel} this
17242 "selectionchange" : true,
17244 * @event afterselectionchange
17245 * Fires after the selection changes (eg. by key press or clicking)
17246 * @param {SelectionModel} this
17248 "afterselectionchange" : true,
17250 * @event beforerowselect
17251 * Fires when a row is selected being selected, return false to cancel.
17252 * @param {SelectionModel} this
17253 * @param {Number} rowIndex The selected index
17254 * @param {Boolean} keepExisting False if other selections will be cleared
17256 "beforerowselect" : true,
17259 * Fires when a row is selected.
17260 * @param {SelectionModel} this
17261 * @param {Number} rowIndex The selected index
17262 * @param {Roo.data.Record} r The record
17264 "rowselect" : true,
17266 * @event rowdeselect
17267 * Fires when a row is deselected.
17268 * @param {SelectionModel} this
17269 * @param {Number} rowIndex The selected index
17271 "rowdeselect" : true
17273 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
17274 this.locked = false;
17277 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
17279 * @cfg {Boolean} singleSelect
17280 * True to allow selection of only one row at a time (defaults to false)
17282 singleSelect : false,
17285 initEvents : function(){
17287 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
17288 this.grid.on("mousedown", this.handleMouseDown, this);
17289 }else{ // allow click to work like normal
17290 this.grid.on("rowclick", this.handleDragableRowClick, this);
17293 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
17294 "up" : function(e){
17296 this.selectPrevious(e.shiftKey);
17297 }else if(this.last !== false && this.lastActive !== false){
17298 var last = this.last;
17299 this.selectRange(this.last, this.lastActive-1);
17300 this.grid.getView().focusRow(this.lastActive);
17301 if(last !== false){
17305 this.selectFirstRow();
17307 this.fireEvent("afterselectionchange", this);
17309 "down" : function(e){
17311 this.selectNext(e.shiftKey);
17312 }else if(this.last !== false && this.lastActive !== false){
17313 var last = this.last;
17314 this.selectRange(this.last, this.lastActive+1);
17315 this.grid.getView().focusRow(this.lastActive);
17316 if(last !== false){
17320 this.selectFirstRow();
17322 this.fireEvent("afterselectionchange", this);
17327 var view = this.grid.view;
17328 view.on("refresh", this.onRefresh, this);
17329 view.on("rowupdated", this.onRowUpdated, this);
17330 view.on("rowremoved", this.onRemove, this);
17334 onRefresh : function(){
17335 var ds = this.grid.dataSource, i, v = this.grid.view;
17336 var s = this.selections;
17337 s.each(function(r){
17338 if((i = ds.indexOfId(r.id)) != -1){
17347 onRemove : function(v, index, r){
17348 this.selections.remove(r);
17352 onRowUpdated : function(v, index, r){
17353 if(this.isSelected(r)){
17354 v.onRowSelect(index);
17360 * @param {Array} records The records to select
17361 * @param {Boolean} keepExisting (optional) True to keep existing selections
17363 selectRecords : function(records, keepExisting){
17365 this.clearSelections();
17367 var ds = this.grid.dataSource;
17368 for(var i = 0, len = records.length; i < len; i++){
17369 this.selectRow(ds.indexOf(records[i]), true);
17374 * Gets the number of selected rows.
17377 getCount : function(){
17378 return this.selections.length;
17382 * Selects the first row in the grid.
17384 selectFirstRow : function(){
17389 * Select the last row.
17390 * @param {Boolean} keepExisting (optional) True to keep existing selections
17392 selectLastRow : function(keepExisting){
17393 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
17397 * Selects the row immediately following the last selected row.
17398 * @param {Boolean} keepExisting (optional) True to keep existing selections
17400 selectNext : function(keepExisting){
17401 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
17402 this.selectRow(this.last+1, keepExisting);
17403 this.grid.getView().focusRow(this.last);
17408 * Selects the row that precedes the last selected row.
17409 * @param {Boolean} keepExisting (optional) True to keep existing selections
17411 selectPrevious : function(keepExisting){
17413 this.selectRow(this.last-1, keepExisting);
17414 this.grid.getView().focusRow(this.last);
17419 * Returns the selected records
17420 * @return {Array} Array of selected records
17422 getSelections : function(){
17423 return [].concat(this.selections.items);
17427 * Returns the first selected record.
17430 getSelected : function(){
17431 return this.selections.itemAt(0);
17436 * Clears all selections.
17438 clearSelections : function(fast){
17439 if(this.locked) return;
17441 var ds = this.grid.dataSource;
17442 var s = this.selections;
17443 s.each(function(r){
17444 this.deselectRow(ds.indexOfId(r.id));
17448 this.selections.clear();
17455 * Selects all rows.
17457 selectAll : function(){
17458 if(this.locked) return;
17459 this.selections.clear();
17460 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
17461 this.selectRow(i, true);
17466 * Returns True if there is a selection.
17467 * @return {Boolean}
17469 hasSelection : function(){
17470 return this.selections.length > 0;
17474 * Returns True if the specified row is selected.
17475 * @param {Number/Record} record The record or index of the record to check
17476 * @return {Boolean}
17478 isSelected : function(index){
17479 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
17480 return (r && this.selections.key(r.id) ? true : false);
17484 * Returns True if the specified record id is selected.
17485 * @param {String} id The id of record to check
17486 * @return {Boolean}
17488 isIdSelected : function(id){
17489 return (this.selections.key(id) ? true : false);
17493 handleMouseDown : function(e, t){
17494 var view = this.grid.getView(), rowIndex;
17495 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
17498 if(e.shiftKey && this.last !== false){
17499 var last = this.last;
17500 this.selectRange(last, rowIndex, e.ctrlKey);
17501 this.last = last; // reset the last
17502 view.focusRow(rowIndex);
17504 var isSelected = this.isSelected(rowIndex);
17505 if(e.button !== 0 && isSelected){
17506 view.focusRow(rowIndex);
17507 }else if(e.ctrlKey && isSelected){
17508 this.deselectRow(rowIndex);
17509 }else if(!isSelected){
17510 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
17511 view.focusRow(rowIndex);
17514 this.fireEvent("afterselectionchange", this);
17517 handleDragableRowClick : function(grid, rowIndex, e)
17519 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
17520 this.selectRow(rowIndex, false);
17521 grid.view.focusRow(rowIndex);
17522 this.fireEvent("afterselectionchange", this);
17527 * Selects multiple rows.
17528 * @param {Array} rows Array of the indexes of the row to select
17529 * @param {Boolean} keepExisting (optional) True to keep existing selections
17531 selectRows : function(rows, keepExisting){
17533 this.clearSelections();
17535 for(var i = 0, len = rows.length; i < len; i++){
17536 this.selectRow(rows[i], true);
17541 * Selects a range of rows. All rows in between startRow and endRow are also selected.
17542 * @param {Number} startRow The index of the first row in the range
17543 * @param {Number} endRow The index of the last row in the range
17544 * @param {Boolean} keepExisting (optional) True to retain existing selections
17546 selectRange : function(startRow, endRow, keepExisting){
17547 if(this.locked) return;
17549 this.clearSelections();
17551 if(startRow <= endRow){
17552 for(var i = startRow; i <= endRow; i++){
17553 this.selectRow(i, true);
17556 for(var i = startRow; i >= endRow; i--){
17557 this.selectRow(i, true);
17563 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
17564 * @param {Number} startRow The index of the first row in the range
17565 * @param {Number} endRow The index of the last row in the range
17567 deselectRange : function(startRow, endRow, preventViewNotify){
17568 if(this.locked) return;
17569 for(var i = startRow; i <= endRow; i++){
17570 this.deselectRow(i, preventViewNotify);
17576 * @param {Number} row The index of the row to select
17577 * @param {Boolean} keepExisting (optional) True to keep existing selections
17579 selectRow : function(index, keepExisting, preventViewNotify){
17580 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17581 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17582 if(!keepExisting || this.singleSelect){
17583 this.clearSelections();
17585 var r = this.grid.dataSource.getAt(index);
17586 this.selections.add(r);
17587 this.last = this.lastActive = index;
17588 if(!preventViewNotify){
17589 this.grid.getView().onRowSelect(index);
17591 this.fireEvent("rowselect", this, index, r);
17592 this.fireEvent("selectionchange", this);
17598 * @param {Number} row The index of the row to deselect
17600 deselectRow : function(index, preventViewNotify){
17601 if(this.locked) return;
17602 if(this.last == index){
17605 if(this.lastActive == index){
17606 this.lastActive = false;
17608 var r = this.grid.dataSource.getAt(index);
17609 this.selections.remove(r);
17610 if(!preventViewNotify){
17611 this.grid.getView().onRowDeselect(index);
17613 this.fireEvent("rowdeselect", this, index);
17614 this.fireEvent("selectionchange", this);
17618 restoreLast : function(){
17620 this.last = this._last;
17625 acceptsNav : function(row, col, cm){
17626 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17630 onEditorKey : function(field, e){
17631 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17636 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17638 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17640 }else if(k == e.ENTER && !e.ctrlKey){
17644 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17646 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17648 }else if(k == e.ESC){
17652 g.startEditing(newCell[0], newCell[1]);
17657 * Ext JS Library 1.1.1
17658 * Copyright(c) 2006-2007, Ext JS, LLC.
17660 * Originally Released Under LGPL - original licence link has changed is not relivant.
17663 * <script type="text/javascript">
17667 * @class Roo.bootstrap.PagingToolbar
17669 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
17671 * Create a new PagingToolbar
17672 * @param {Object} config The config object
17674 Roo.bootstrap.PagingToolbar = function(config)
17676 // old args format still supported... - xtype is prefered..
17677 // created from xtype...
17678 var ds = config.dataSource;
17679 this.toolbarItems = [];
17680 if (config.items) {
17681 this.toolbarItems = config.items;
17682 // config.items = [];
17685 Roo.bootstrap.PagingToolbar.superclass.constructor.call(this, config);
17692 this.navgroup = new Roo.bootstrap.NavGroup({ cls: 'pagination' });
17696 Roo.extend(Roo.bootstrap.PagingToolbar, Roo.bootstrap.NavSimplebar, {
17698 * @cfg {Roo.data.Store} dataSource
17699 * The underlying data store providing the paged data
17702 * @cfg {String/HTMLElement/Element} container
17703 * container The id or element that will contain the toolbar
17706 * @cfg {Boolean} displayInfo
17707 * True to display the displayMsg (defaults to false)
17710 * @cfg {Number} pageSize
17711 * The number of records to display per page (defaults to 20)
17715 * @cfg {String} displayMsg
17716 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
17718 displayMsg : 'Displaying {0} - {1} of {2}',
17720 * @cfg {String} emptyMsg
17721 * The message to display when no records are found (defaults to "No data to display")
17723 emptyMsg : 'No data to display',
17725 * Customizable piece of the default paging text (defaults to "Page")
17728 beforePageText : "Page",
17730 * Customizable piece of the default paging text (defaults to "of %0")
17733 afterPageText : "of {0}",
17735 * Customizable piece of the default paging text (defaults to "First Page")
17738 firstText : "First Page",
17740 * Customizable piece of the default paging text (defaults to "Previous Page")
17743 prevText : "Previous Page",
17745 * Customizable piece of the default paging text (defaults to "Next Page")
17748 nextText : "Next Page",
17750 * Customizable piece of the default paging text (defaults to "Last Page")
17753 lastText : "Last Page",
17755 * Customizable piece of the default paging text (defaults to "Refresh")
17758 refreshText : "Refresh",
17762 onRender : function(ct, position)
17764 Roo.bootstrap.PagingToolbar.superclass.onRender.call(this, ct, position);
17765 this.navgroup.parentId = this.id;
17766 this.navgroup.onRender(this.el, null);
17767 // add the buttons to the navgroup
17769 if(this.displayInfo){
17770 Roo.log(this.el.select('ul.navbar-nav',true).first());
17771 this.el.select('ul.navbar-nav',true).first().createChild({cls:'x-paging-info'});
17772 this.displayEl = this.el.select('.x-paging-info', true).first();
17773 // var navel = this.navgroup.addItem( { tagtype : 'span', html : '', cls : 'x-paging-info', preventDefault : true } );
17774 // this.displayEl = navel.el.select('span',true).first();
17780 Roo.each(_this.buttons, function(e){
17781 Roo.factory(e).onRender(_this.el, null);
17785 Roo.each(_this.toolbarItems, function(e) {
17786 _this.navgroup.addItem(e);
17789 this.first = this.navgroup.addItem({
17790 tooltip: this.firstText,
17792 icon : 'fa fa-backward',
17794 listeners : { click : this.onClick.createDelegate(this, ["first"]) }
17797 this.prev = this.navgroup.addItem({
17798 tooltip: this.prevText,
17800 icon : 'fa fa-step-backward',
17802 listeners : { click : this.onClick.createDelegate(this, ["prev"]) }
17804 //this.addSeparator();
17807 var field = this.navgroup.addItem( {
17809 cls : 'x-paging-position',
17811 html : this.beforePageText +
17812 '<input type="text" size="3" value="1" class="x-grid-page-number">' +
17813 '<span class="x-paging-after">' + String.format(this.afterPageText, 1) + '</span>'
17816 this.field = field.el.select('input', true).first();
17817 this.field.on("keydown", this.onPagingKeydown, this);
17818 this.field.on("focus", function(){this.dom.select();});
17821 this.afterTextEl = field.el.select('.x-paging-after',true).first();
17822 //this.field.setHeight(18);
17823 //this.addSeparator();
17824 this.next = this.navgroup.addItem({
17825 tooltip: this.nextText,
17827 html : ' <i class="fa fa-step-forward">',
17829 listeners : { click : this.onClick.createDelegate(this, ["next"]) }
17831 this.last = this.navgroup.addItem({
17832 tooltip: this.lastText,
17833 icon : 'fa fa-forward',
17836 listeners : { click : this.onClick.createDelegate(this, ["last"]) }
17838 //this.addSeparator();
17839 this.loading = this.navgroup.addItem({
17840 tooltip: this.refreshText,
17841 icon: 'fa fa-refresh',
17843 listeners : { click : this.onClick.createDelegate(this, ["refresh"]) }
17849 updateInfo : function(){
17850 if(this.displayEl){
17851 var count = this.ds.getCount();
17852 var msg = count == 0 ?
17856 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
17858 this.displayEl.update(msg);
17863 onLoad : function(ds, r, o){
17864 this.cursor = o.params ? o.params.start : 0;
17865 var d = this.getPageData(),
17869 this.afterTextEl.dom.innerHTML = String.format(this.afterPageText, d.pages);
17870 this.field.dom.value = ap;
17871 this.first.setDisabled(ap == 1);
17872 this.prev.setDisabled(ap == 1);
17873 this.next.setDisabled(ap == ps);
17874 this.last.setDisabled(ap == ps);
17875 this.loading.enable();
17880 getPageData : function(){
17881 var total = this.ds.getTotalCount();
17884 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
17885 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
17890 onLoadError : function(){
17891 this.loading.enable();
17895 onPagingKeydown : function(e){
17896 var k = e.getKey();
17897 var d = this.getPageData();
17899 var v = this.field.dom.value, pageNum;
17900 if(!v || isNaN(pageNum = parseInt(v, 10))){
17901 this.field.dom.value = d.activePage;
17904 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
17905 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17908 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))
17910 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
17911 this.field.dom.value = pageNum;
17912 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
17915 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17917 var v = this.field.dom.value, pageNum;
17918 var increment = (e.shiftKey) ? 10 : 1;
17919 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
17921 if(!v || isNaN(pageNum = parseInt(v, 10))) {
17922 this.field.dom.value = d.activePage;
17925 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
17927 this.field.dom.value = parseInt(v, 10) + increment;
17928 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
17929 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
17936 beforeLoad : function(){
17938 this.loading.disable();
17943 onClick : function(which){
17950 ds.load({params:{start: 0, limit: this.pageSize}});
17953 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
17956 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
17959 var total = ds.getTotalCount();
17960 var extra = total % this.pageSize;
17961 var lastStart = extra ? (total - extra) : total-this.pageSize;
17962 ds.load({params:{start: lastStart, limit: this.pageSize}});
17965 ds.load({params:{start: this.cursor, limit: this.pageSize}});
17971 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
17972 * @param {Roo.data.Store} store The data store to unbind
17974 unbind : function(ds){
17975 ds.un("beforeload", this.beforeLoad, this);
17976 ds.un("load", this.onLoad, this);
17977 ds.un("loadexception", this.onLoadError, this);
17978 ds.un("remove", this.updateInfo, this);
17979 ds.un("add", this.updateInfo, this);
17980 this.ds = undefined;
17984 * Binds the paging toolbar to the specified {@link Roo.data.Store}
17985 * @param {Roo.data.Store} store The data store to bind
17987 bind : function(ds){
17988 ds.on("beforeload", this.beforeLoad, this);
17989 ds.on("load", this.onLoad, this);
17990 ds.on("loadexception", this.onLoadError, this);
17991 ds.on("remove", this.updateInfo, this);
17992 ds.on("add", this.updateInfo, this);
18003 * @class Roo.bootstrap.MessageBar
18004 * @extends Roo.bootstrap.Component
18005 * Bootstrap MessageBar class
18006 * @cfg {String} html contents of the MessageBar
18007 * @cfg {String} weight (info | success | warning | danger) default info
18008 * @cfg {String} beforeClass insert the bar before the given class
18009 * @cfg {Boolean} closable (true | false) default false
18010 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
18013 * Create a new Element
18014 * @param {Object} config The config object
18017 Roo.bootstrap.MessageBar = function(config){
18018 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
18021 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
18027 beforeClass: 'bootstrap-sticky-wrap',
18029 getAutoCreate : function(){
18033 cls: 'alert alert-dismissable alert-' + this.weight,
18038 html: this.html || ''
18044 cfg.cls += ' alert-messages-fixed';
18058 onRender : function(ct, position)
18060 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
18063 var cfg = Roo.apply({}, this.getAutoCreate());
18067 cfg.cls += ' ' + this.cls;
18070 cfg.style = this.style;
18072 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
18074 this.el.setVisibilityMode(Roo.Element.DISPLAY);
18077 this.el.select('>button.close').on('click', this.hide, this);
18083 if (!this.rendered) {
18089 this.fireEvent('show', this);
18095 if (!this.rendered) {
18101 this.fireEvent('hide', this);
18104 update : function()
18106 // var e = this.el.dom.firstChild;
18108 // if(this.closable){
18109 // e = e.nextSibling;
18112 // e.data = this.html || '';
18114 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';
18130 * @class Roo.bootstrap.Graph
18131 * @extends Roo.bootstrap.Component
18132 * Bootstrap Graph class
18136 @cfg {String} graphtype bar | vbar | pie
18137 @cfg {number} g_x coodinator | centre x (pie)
18138 @cfg {number} g_y coodinator | centre y (pie)
18139 @cfg {number} g_r radius (pie)
18140 @cfg {number} g_height height of the chart (respected by all elements in the set)
18141 @cfg {number} g_width width of the chart (respected by all elements in the set)
18142 @cfg {Object} title The title of the chart
18145 -opts (object) options for the chart
18147 o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
18148 o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
18150 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.
18151 o stacked (boolean) whether or not to tread values as in a stacked bar chart
18153 o stretch (boolean)
18155 -opts (object) options for the pie
18158 o startAngle (number)
18159 o endAngle (number)
18163 * Create a new Input
18164 * @param {Object} config The config object
18167 Roo.bootstrap.Graph = function(config){
18168 Roo.bootstrap.Graph.superclass.constructor.call(this, config);
18174 * The img click event for the img.
18175 * @param {Roo.EventObject} e
18181 Roo.extend(Roo.bootstrap.Graph, Roo.bootstrap.Component, {
18192 //g_colors: this.colors,
18199 getAutoCreate : function(){
18210 onRender : function(ct,position){
18211 Roo.bootstrap.Graph.superclass.onRender.call(this,ct,position);
18212 this.raphael = Raphael(this.el.dom);
18214 // data1 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18215 // data2 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18216 // data3 = [[55, 20, 13, 32, 5, 1, 2, 10], [10, 2, 1, 5, 32, 13, 20, 55], [12, 20, 30]],
18217 // txtattr = { font: "12px 'Fontin Sans', Fontin-Sans, sans-serif" };
18219 r.text(160, 10, "Single Series Chart").attr(txtattr);
18220 r.text(480, 10, "Multiline Series Chart").attr(txtattr);
18221 r.text(160, 250, "Multiple Series Stacked Chart").attr(txtattr);
18222 r.text(480, 250, 'Multiline Series Stacked Vertical Chart. Type "round"').attr(txtattr);
18224 r.barchart(10, 10, 300, 220, [[55, 20, 13, 32, 5, 1, 2, 10]], 0, {type: "sharp"});
18225 r.barchart(330, 10, 300, 220, data1);
18226 r.barchart(10, 250, 300, 220, data2, {stacked: true});
18227 r.barchart(330, 250, 300, 220, data3, {stacked: true, type: "round"});
18230 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18231 // r.barchart(30, 30, 560, 250, xdata, {
18232 // labels : [55, 20, 13, 32, 5, 1, 2, 10,5 , 10],
18233 // axis : "0 0 1 1",
18234 // axisxlabels : xdata
18235 // //yvalues : cols,
18238 // var xdata = [55, 20, 13, 32, 5, 1, 2, 10,5 , 10];
18240 // this.load(null,xdata,{
18241 // axis : "0 0 1 1",
18242 // axisxlabels : xdata
18247 load : function(graphtype,xdata,opts){
18248 this.raphael.clear();
18250 graphtype = this.graphtype;
18255 var r = this.raphael,
18256 fin = function () {
18257 this.flag = r.popup(this.bar.x, this.bar.y, this.bar.value || "0").insertBefore(this);
18259 fout = function () {
18260 this.flag.animate({opacity: 0}, 300, function () {this.remove();});
18265 this.raphael.barchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18268 this.raphael.hbarchart(this.g_x,this.g_y,this.g_width,this.g_height,xdata,opts).hover(fin,fout);
18271 opts = { legend: ["%% - Enterprise Users", "% - ddd","Chrome Users"], legendpos: "west",
18272 href: ["http://raphaeljs.com", "http://g.raphaeljs.com"]};
18274 this.raphael.piechart(this.g_x,this.g_y,this.g_r,xdata,opts);
18281 this.raphael.text(this.title.x, this.title.y, this.title.text).attr(this.title.attr);
18286 setTitle: function(o)
18291 initEvents: function() {
18294 this.el.on('click', this.onClick, this);
18298 onClick : function(e)
18300 Roo.log('img onclick');
18301 this.fireEvent('click', this, e);
18313 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18316 * @class Roo.bootstrap.dash.NumberBox
18317 * @extends Roo.bootstrap.Component
18318 * Bootstrap NumberBox class
18319 * @cfg {String} bgcolor Box background color, such as (aqua | green | yellow | red etc..) Default aqua
18320 * @cfg {String} headline Box headline
18321 * @cfg {String} content Box content
18322 * @cfg {String} icon Box icon
18323 * @cfg {String} footer Footer text
18324 * @cfg {String} fhref Footer href
18327 * Create a new NumberBox
18328 * @param {Object} config The config object
18332 Roo.bootstrap.dash.NumberBox = function(config){
18333 Roo.bootstrap.dash.NumberBox.superclass.constructor.call(this, config);
18337 Roo.extend(Roo.bootstrap.dash.NumberBox, Roo.bootstrap.Component, {
18347 getAutoCreate : function(){
18351 cls : 'small-box bg-' + this.bgcolor,
18359 cls : 'roo-headline',
18360 html : this.headline
18364 cls : 'roo-content',
18365 html : this.content
18379 cls : 'ion ' + this.icon
18388 cls : 'small-box-footer',
18389 href : this.fhref || '#',
18393 cfg.cn.push(footer);
18400 onRender : function(ct,position){
18401 Roo.bootstrap.dash.NumberBox.superclass.onRender.call(this,ct,position);
18408 setHeadline: function (value)
18410 this.el.select('.roo-headline',true).first().dom.innerHTML = value;
18414 initEvents: function()
18428 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18431 * @class Roo.bootstrap.dash.TabBox
18432 * @extends Roo.bootstrap.Component
18433 * Bootstrap TabBox class
18434 * @cfg {String} title Title of the TabBox
18435 * @cfg {String} icon Icon of the TabBox
18438 * Create a new TabBox
18439 * @param {Object} config The config object
18443 Roo.bootstrap.dash.TabBox = function(config){
18444 Roo.bootstrap.dash.TabBox.superclass.constructor.call(this, config);
18448 Roo.extend(Roo.bootstrap.dash.TabBox, Roo.bootstrap.Component, {
18453 getChildContainer : function()
18455 return this.el.select('.tab-content', true).first();
18458 getAutoCreate : function(){
18462 cls: 'pull-left header',
18470 cls: 'fa ' + this.icon
18477 cls: 'nav-tabs-custom',
18481 cls: 'nav nav-tabs pull-right',
18488 cls: 'tab-content no-padding',
18497 setTitle : function(value)
18499 this.el.select('.header', true).first().dom.innerHTML = value;
18511 Roo.bootstrap.dash = Roo.bootstrap.dash || {};
18513 * @class Roo.bootstrap.TabPane
18514 * @extends Roo.bootstrap.Component
18515 * Bootstrap TabPane class
18516 * @cfg {Boolean} active (false | true) Default false
18520 * Create a new TabPane
18521 * @param {Object} config The config object
18524 Roo.bootstrap.dash.TabPane = function(config){
18525 Roo.bootstrap.dash.TabPane.superclass.constructor.call(this, config);
18529 Roo.extend(Roo.bootstrap.dash.TabPane, Roo.bootstrap.Component, {
18533 // getBox : function()
18535 // return this.el.findParent('.nav-tabs-custom', false, true);
18538 getAutoCreate : function()
18546 cfg.cls += ' active';
18564 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
18567 * @class Roo.bootstrap.menu.Menu
18568 * @extends Roo.bootstrap.Component
18569 * Bootstrap Menu class - container for Menu
18570 * @cfg {String} html Text of the menu
18571 * @cfg {String} weight (default | primary | success | info | warning | danger | inverse)
18572 * @cfg {String} icon Font awesome icon
18573 * @cfg {String} pos Menu align to (top | bottom) default bottom
18577 * Create a new Menu
18578 * @param {Object} config The config object
18582 Roo.bootstrap.menu.Menu = function(config){
18583 Roo.bootstrap.menu.Menu.superclass.constructor.call(this, config);
18587 * @event beforeshow
18588 * Fires before this menu is displayed
18589 * @param {Roo.bootstrap.menu.Menu} this
18593 * @event beforehide
18594 * Fires before this menu is hidden
18595 * @param {Roo.bootstrap.menu.Menu} this
18600 * Fires after this menu is displayed
18601 * @param {Roo.bootstrap.menu.Menu} this
18606 * Fires after this menu is hidden
18607 * @param {Roo.bootstrap.menu.Menu} this
18612 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
18613 * @param {Roo.bootstrap.menu.Menu} this
18614 * @param {Roo.EventObject} e
18621 Roo.extend(Roo.bootstrap.menu.Menu, Roo.bootstrap.Component, {
18625 weight : 'default',
18630 getChildContainer : function() {
18631 if(this.isSubMenu()){
18635 return this.el.select('ul.dropdown-menu', true).first();
18638 getAutoCreate : function()
18643 cls : 'roo-menu-text',
18651 cls : 'fa ' + this.icon
18662 cls : 'dropdown-button btn btn-' + this.weight,
18667 cls : 'dropdown-toggle btn btn-' + this.weight,
18677 cls : 'dropdown-menu'
18683 if(this.pos == 'top'){
18684 cfg.cls += ' dropup';
18687 if(this.isSubMenu()){
18690 cls : 'dropdown-menu'
18697 isSubMenu : function()
18699 if(this.parent() instanceof Roo.bootstrap.menu.Item){
18707 initEvents : function()
18710 if(this.isSubMenu()){
18714 this.hidden = true;
18716 this.triggerEl = this.el.select('button.dropdown-toggle', true).first();
18717 this.triggerEl.on('click', this.onTriggerPress, this);
18719 this.buttonEl = this.el.select('button.dropdown-button', true).first();
18720 this.buttonEl.on('click', this.onClick, this);
18724 onClick : function(e)
18726 this.fireEvent("click", this, e);
18729 onTriggerPress : function(e)
18731 if (this.isVisible()) {
18738 isVisible : function(){
18739 return !this.hidden;
18744 this.fireEvent("beforeshow", this);
18746 this.hidden = false;
18747 this.el.addClass('open');
18749 Roo.get(document).on("mouseup", this.onMouseUp, this);
18751 this.fireEvent("show", this);
18757 this.fireEvent("beforehide", this);
18759 this.hidden = true;
18760 this.el.removeClass('open');
18762 Roo.get(document).un("mouseup", this.onMouseUp);
18764 this.fireEvent("hide", this);
18767 onMouseUp : function()
18781 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
18784 * @class Roo.bootstrap.menu.Item
18785 * @extends Roo.bootstrap.Component
18786 * Bootstrap MenuItem class
18787 * @cfg {Boolean} submenu (true | false) default false
18788 * @cfg {String} html text of the item
18789 * @cfg {String} href the link
18790 * @cfg {Boolean} disable (true | false) default false
18791 * @cfg {Boolean} preventDefault (true | false) default true
18792 * @cfg {String} icon Font awesome icon
18793 * @cfg {String} pos Submenu align to (left | right) default right
18797 * Create a new Item
18798 * @param {Object} config The config object
18802 Roo.bootstrap.menu.Item = function(config){
18803 Roo.bootstrap.menu.Item.superclass.constructor.call(this, config);
18807 * Fires when the mouse is hovering over this menu
18808 * @param {Roo.bootstrap.menu.Item} this
18809 * @param {Roo.EventObject} e
18814 * Fires when the mouse exits this menu
18815 * @param {Roo.bootstrap.menu.Item} this
18816 * @param {Roo.EventObject} e
18822 * The raw click event for the entire grid.
18823 * @param {Roo.EventObject} e
18829 Roo.extend(Roo.bootstrap.menu.Item, Roo.bootstrap.Component, {
18834 preventDefault: true,
18839 getAutoCreate : function()
18844 cls : 'roo-menu-item-text',
18852 cls : 'fa ' + this.icon
18861 href : this.href || '#',
18868 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'disabled' : (cfg.cls + ' disabled');
18872 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'dropdown-submenu' : (cfg.cls + ' dropdown-submenu');
18874 if(this.pos == 'left'){
18875 cfg.cls = (typeof(cfg.cls) == 'undefined') ? 'pull-left' : (cfg.cls + ' pull-left');
18882 initEvents : function()
18884 this.el.on('mouseover', this.onMouseOver, this);
18885 this.el.on('mouseout', this.onMouseOut, this);
18887 this.el.select('a', true).first().on('click', this.onClick, this);
18891 onClick : function(e)
18893 if(this.preventDefault){
18894 e.preventDefault();
18897 this.fireEvent("click", this, e);
18900 onMouseOver : function(e)
18902 this.fireEvent("mouseover", this, e);
18905 onMouseOut : function(e)
18907 this.fireEvent("mouseout", this, e);
18919 Roo.bootstrap.menu = Roo.bootstrap.menu || {};
18922 * @class Roo.bootstrap.menu.Separator
18923 * @extends Roo.bootstrap.Component
18924 * Bootstrap Separator class
18927 * Create a new Separator
18928 * @param {Object} config The config object
18932 Roo.bootstrap.menu.Separator = function(config){
18933 Roo.bootstrap.menu.Separator.superclass.constructor.call(this, config);
18936 Roo.extend(Roo.bootstrap.menu.Separator, Roo.bootstrap.Component, {
18938 getAutoCreate : function(){