4 * base class for bootstrap elements.
8 Roo.bootstrap = Roo.bootstrap || {};
10 * @class Roo.bootstrap.Component
11 * @extends Roo.Component
12 * Bootstrap Component base class
13 * @cfg {String} cls css class
14 * @cfg {String} style any extra css
15 * @cfg {Object} xattr extra attributes to add to 'element' (used by builder to store stuff.)
16 * @cfg {Boolean} can_build_overlaid True if element can be rebuild from a HTML page
17 * @cfg {string} dataId cutomer id
18 * @cfg {string} name Specifies name attribute
21 * Do not use directly - it does not do anything..
22 * @param {Object} config The config object
27 Roo.bootstrap.Component = function(config){
28 Roo.bootstrap.Component.superclass.constructor.call(this, config);
31 Roo.extend(Roo.bootstrap.Component, Roo.BoxComponent, {
34 allowDomMove : false, // to stop relocations in parent onRender...
42 initEvents : function() { },
48 can_build_overlaid : true,
55 // returns the parent component..
56 return Roo.ComponentMgr.get(this.parentId)
62 onRender : function(ct, position)
64 // Roo.log("Call onRender: " + this.xtype);
66 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
69 if (this.el.attr('xtype')) {
70 this.el.attr('xtypex', this.el.attr('xtype'));
71 this.el.dom.removeAttribute('xtype');
81 var cfg = Roo.apply({}, this.getAutoCreate());
84 // fill in the extra attributes
85 if (this.xattr && typeof(this.xattr) =='object') {
86 for (var i in this.xattr) {
87 cfg[i] = this.xattr[i];
92 cfg.dataId = this.dataId;
96 cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls;
99 if (this.style) { // fixme needs to support more complex style data.
100 cfg.style = this.style;
104 cfg.name = this.name;
107 this.el = ct.createChild(cfg, position);
109 if(this.tabIndex !== undefined){
110 this.el.dom.setAttribute('tabIndex', this.tabIndex);
117 getChildContainer : function()
123 addxtype : function(tree,cntr)
127 cn = Roo.factory(tree);
129 cn.parentType = this.xtype; //??
130 cn.parentId = this.id;
132 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
134 var has_flexy_each = (typeof(tree['flexy:foreach']) != 'undefined');
136 var has_flexy_if = (typeof(tree['flexy:if']) != 'undefined');
138 var build_from_html = Roo.XComponent.build_from_html;
140 var is_body = (tree.xtype == 'Body') ;
142 var page_has_body = (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body');
144 var self_cntr_el = Roo.get(this[cntr]());
146 if (!has_flexy_each || !build_from_html || is_body || !page_has_body) {
147 if(!has_flexy_if || typeof(tree.name) == 'undefined' || !build_from_html || is_body || !page_has_body){
148 return this.addxtypeChild(tree,cntr);
151 var echild =self_cntr_el ? self_cntr_el.child('>*[name=' + tree.name + ']') : false;
154 return this.addxtypeChild(Roo.apply({}, tree),cntr);
157 Roo.log('skipping render');
165 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
171 if (echild && echild.attr('xtype').split('.').pop() != cn.xtype) {
175 ret = this.addxtypeChild(Roo.apply({}, tree),cntr);
180 addxtypeChild : function (tree, cntr)
182 Roo.log('addxtypeChild:' + cntr);
184 cntr = (typeof(cntr) == 'undefined' ) ? 'getChildContainer' : cntr;
187 var has_flexy = (typeof(tree['flexy:if']) != 'undefined') ||
188 (typeof(tree['flexy:foreach']) != 'undefined');
193 // render the element if it's not BODY.
194 if (tree.xtype != 'Body') {
196 cn = Roo.factory(tree);
198 cn.parentType = this.xtype; //??
199 cn.parentId = this.id;
201 var build_from_html = Roo.XComponent.build_from_html;
204 // does the container contain child eleemnts with 'xtype' attributes.
205 // that match this xtype..
206 // note - when we render we create these as well..
207 // so we should check to see if body has xtype set.
208 if (Roo.get(document.body).attr('xtype') == 'Roo.bootstrap.Body') {
210 var self_cntr_el = Roo.get(this[cntr]());
211 var echild =self_cntr_el ? self_cntr_el.child('>*[xtype]') : false;
213 if (echild && echild.attr('xtype').split('.').pop() == cn.xtype) {
214 // Roo.log("found child for " + this.xtype +": " + echild.attr('xtype') );
220 //echild.dom.removeAttribute('xtype');
222 Roo.log("MISSING " + cn.xtype + " on child of " + (this.el ? this.el.attr('xbuilderid') : 'no parent'));
229 // if object has flexy:if - then it may or may not be rendered.
230 if (build_from_html && has_flexy && !cn.el && cn.can_build_overlaid) {
231 // skip a flexy if element.
232 Roo.log('skipping render');
235 // actually if flexy:foreach is found, we really want to create
236 // multiple copies here...
238 //Roo.log(this[cntr]());
239 cn.render(this[cntr]());
241 // then add the element..
248 if (typeof (tree.menu) != 'undefined') {
249 tree.menu.parentType = cn.xtype;
250 tree.menu.triggerEl = cn.el;
251 nitems.push(cn.addxtype(Roo.apply({}, tree.menu)));
255 if (!tree.items || !tree.items.length) {
259 var items = tree.items;
262 //Roo.log(items.length);
264 for(var i =0;i < items.length;i++) {
265 nitems.push(cn.addxtype(Roo.apply({}, items[i])));
286 * @class Roo.bootstrap.Body
287 * @extends Roo.bootstrap.Component
288 * Bootstrap Body class
292 * @param {Object} config The config object
295 Roo.bootstrap.Body = function(config){
296 Roo.bootstrap.Body.superclass.constructor.call(this, config);
297 this.el = Roo.get(document.body);
298 if (this.cls && this.cls.length) {
299 Roo.get(document.body).addClass(this.cls);
303 Roo.extend(Roo.bootstrap.Body, Roo.bootstrap.Component, {
308 onRender : function(ct, position)
310 /* Roo.log("Roo.bootstrap.Body - onRender");
311 if (this.cls && this.cls.length) {
312 Roo.get(document.body).addClass(this.cls);
332 * @class Roo.bootstrap.ButtonGroup
333 * @extends Roo.bootstrap.Component
334 * Bootstrap ButtonGroup class
335 * @cfg {String} size lg | sm | xs (default empty normal)
336 * @cfg {String} align vertical | justified (default none)
337 * @cfg {String} direction up | down (default down)
338 * @cfg {Boolean} toolbar false | true
339 * @cfg {Boolean} btn true | false
344 * @param {Object} config The config object
347 Roo.bootstrap.ButtonGroup = function(config){
348 Roo.bootstrap.ButtonGroup.superclass.constructor.call(this, config);
351 Roo.extend(Roo.bootstrap.ButtonGroup, Roo.bootstrap.Component, {
359 getAutoCreate : function(){
365 cfg.html = this.html || cfg.html;
376 if (['vertical','justified'].indexOf(this.align)!==-1) {
377 cfg.cls = 'btn-group-' + this.align;
379 if (this.align == 'justified') {
380 console.log(this.items);
384 if (['lg','sm','xs'].indexOf(this.size)!==-1) {
385 cfg.cls += ' btn-group-' + this.size;
388 if (this.direction == 'up') {
389 cfg.cls += ' dropup' ;
405 * @class Roo.bootstrap.Button
406 * @extends Roo.bootstrap.Component
407 * Bootstrap Button class
408 * @cfg {String} html The button content
409 * @cfg {String} weight default (or empty) | primary | success | info | warning | danger | link
410 * @cfg {String} size empty | lg | sm | xs
411 * @cfg {String} tag empty | a | input | submit
412 * @cfg {String} href empty or href
413 * @cfg {Boolean} disabled false | true
414 * @cfg {Boolean} isClose false | true
415 * @cfg {String} glyphicon empty | adjust | align-center | align-justify | align-left | align-right | arrow-down | arrow-left | arrow-right | arrow-up | asterisk | backward | ban-circle | barcode | bell | bold | book | bookmark | briefcase | bullhorn | calendar | camera | certificate | check | chevron-down | chevron-left | chevron-right | chevron-up | circle-arrow-down | circle-arrow-left | circle-arrow-right | circle-arrow-up | cloud | cloud-download | cloud-upload | cog | collapse-down | collapse-up | comment | compressed | copyright-mark | credit-card | cutlery | dashboard | download | download-alt | earphone | edit | eject | envelope | euro | exclamation-sign | expand | export | eye-close | eye-open | facetime-video | fast-backward | fast-forward | file | film | filter | fire | flag | flash | floppy-disk | floppy-open | floppy-remove | floppy-save | floppy-saved | folder-close | folder-open | font | forward | fullscreen | gbp | gift | glass | globe | hand-down | hand-left | hand-right | hand-up | hd-video | hdd | header | headphones | heart | heart-empty | home | import | inbox | indent-left | indent-right | info-sign | italic | leaf | link | list | list-alt | lock | log-in | log-out | magnet | map-marker | minus | minus-sign | move | music | new-window | off | ok | ok-circle | ok-sign | open | paperclip | pause | pencil | phone | phone-alt | picture | plane | play | play-circle | plus | plus-sign | print | pushpin | qrcode | question-sign | random | record | refresh | registration-mark | remove | remove-circle | remove-sign | repeat | resize-full | resize-horizontal | resize-small | resize-vertical | retweet | road | save | saved | screenshot | sd-video | search | send | share | share-alt | shopping-cart | signal | sort | sort-by-alphabet | sort-by-alphabet-alt | sort-by-attributes | sort-by-attributes-alt | sort-by-order | sort-by-order-alt | sound-5-1 | sound-6-1 | sound-7-1 | sound-dolby | sound-stereo | star | star-empty | stats | step-backward | step-forward | stop | subtitles | tag | tags | tasks | text-height | text-width | th | th-large | th-list | thumbs-down | thumbs-up | time | tint | tower | transfer | trash | tree-conifer | tree-deciduous | unchecked | upload | usd | user | volume-down | volume-off | volume-up | warning-sign | wrench | zoom-in | zoom-out
416 * @cfg {String} badge text for badge
417 * @cfg {String} theme default (or empty) | glow
418 * @cfg {Boolean} inverse false | true
419 * @cfg {Boolean} toggle false | true
420 * @cfg {String} ontext text for on toggle state
421 * @cfg {String} offtext text for off toggle state
422 * @cfg {Boolean} defaulton true | false
423 * @cfg {Boolean} preventDefault (true | false) default true
424 * @cfg {Boolean} removeClass true | false remove the standard class..
425 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
428 * Create a new button
429 * @param {Object} config The config object
433 Roo.bootstrap.Button = function(config){
434 Roo.bootstrap.Button.superclass.constructor.call(this, config);
439 * When a butotn is pressed
440 * @param {Roo.EventObject} e
445 * After the button has been toggles
446 * @param {Roo.EventObject} e
447 * @param {boolean} pressed (also available as button.pressed)
453 Roo.extend(Roo.bootstrap.Button, Roo.bootstrap.Component, {
471 preventDefault: true,
480 getAutoCreate : function(){
488 if (['a', 'button', 'input', 'submit'].indexOf(this.tag) < 0) {
489 throw "Invalid value for tag: " + this.tag + ". must be a, button, input or submit.";
494 cfg.html = '<span class="roo-button-text">' + (this.html || cfg.html) + '</span>';
496 if (this.toggle == true) {
499 cls: 'slider-frame roo-button',
504 'data-off-text':'OFF',
505 cls: 'slider-button',
511 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
512 cfg.cls += ' '+this.weight;
521 cfg["aria-hidden"] = true;
523 cfg.html = "×";
529 if (this.theme==='default') {
530 cfg.cls = 'btn roo-button';
532 //if (this.parentType != 'Navbar') {
533 this.weight = this.weight.length ? this.weight : 'default';
535 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
537 cfg.cls += ' btn-' + this.weight;
539 } else if (this.theme==='glow') {
542 cfg.cls = 'btn-glow roo-button';
544 if (['default', 'primary', 'success', 'info', 'warning', 'danger', 'link'].indexOf(this.weight) > -1) {
546 cfg.cls += ' ' + this.weight;
552 this.cls += ' inverse';
557 cfg.cls += ' active';
561 cfg.disabled = 'disabled';
565 Roo.log('changing to ul' );
567 this.glyphicon = 'caret';
570 cfg.cls += this.size.length ? (' btn-' + this.size) : '';
572 //gsRoo.log(this.parentType);
573 if (this.parentType === 'Navbar' && !this.parent().bar) {
574 Roo.log('changing to li?');
583 href : this.href || '#'
586 cfg.cn[0].html = this.html + ' <span class="caret"></span>';
587 cfg.cls += ' dropdown';
594 cfg.cls += this.parentType === 'Navbar' ? ' navbar-btn' : '';
596 if (this.glyphicon) {
597 cfg.html = ' ' + cfg.html;
602 cls: 'glyphicon glyphicon-' + this.glyphicon
612 // cfg.cls='btn roo-button';
616 var value = cfg.html;
621 cls: 'glyphicon glyphicon-' + this.glyphicon,
640 cfg.cls += ' dropdown';
641 cfg.html = typeof(cfg.html) != 'undefined' ? cfg.html + ' <span class="caret"></span>' : '<span class="caret"></span>';
644 if (cfg.tag !== 'a' && this.href !== '') {
645 throw "Tag must be a to set href.";
646 } else if (this.href.length > 0) {
647 cfg.href = this.href;
650 if(this.removeClass){
655 cfg.target = this.target;
660 initEvents: function() {
661 // Roo.log('init events?');
662 // Roo.log(this.el.dom);
663 if (this.el.hasClass('roo-button')) {
664 this.el.on('click', this.onClick, this);
666 this.el.select('.roo-button').on('click', this.onClick, this);
669 if(this.removeClass){
670 this.el.on('click', this.onClick, this);
673 this.el.enableDisplayMode();
676 onClick : function(e)
682 Roo.log('button on click ');
683 if(this.preventDefault){
686 if (this.pressed === true || this.pressed === false) {
687 this.pressed = !this.pressed;
688 this.el[this.pressed ? 'addClass' : 'removeClass']('active');
689 this.fireEvent('toggle', this, e, this.pressed);
693 this.fireEvent('click', this, e);
697 * Enables this button
701 this.disabled = false;
702 this.el.removeClass('disabled');
706 * Disable this button
710 this.disabled = true;
711 this.el.addClass('disabled');
714 * sets the active state on/off,
715 * @param {Boolean} state (optional) Force a particular state
717 setActive : function(v) {
719 this.el[v ? 'addClass' : 'removeClass']('active');
722 * toggles the current active state
724 toggleActive : function()
726 var active = this.el.hasClass('active');
727 this.setActive(!active);
731 setText : function(str)
733 this.el.select('.roo-button-text',true).first().dom.innerHTML = str;
756 * @class Roo.bootstrap.Column
757 * @extends Roo.bootstrap.Component
758 * Bootstrap Column class
759 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
760 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
761 * @cfg {Number} md colspan out of 12 for computer-sized screens
762 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
763 * @cfg {String} html content of column.
766 * Create a new Column
767 * @param {Object} config The config object
770 Roo.bootstrap.Column = function(config){
771 Roo.bootstrap.Column.superclass.constructor.call(this, config);
774 Roo.extend(Roo.bootstrap.Column, Roo.bootstrap.Component, {
783 getAutoCreate : function(){
784 var cfg = Roo.apply({}, Roo.bootstrap.Column.superclass.getAutoCreate.call(this));
792 ['xs','sm','md','lg'].map(function(size){
793 if (settings[size]) {
794 cfg.cls += ' col-' + size + '-' + settings[size];
797 if (this.html.length) {
798 cfg.html = this.html;
817 * @class Roo.bootstrap.Container
818 * @extends Roo.bootstrap.Component
819 * Bootstrap Container class
820 * @cfg {Boolean} jumbotron is it a jumbotron element
821 * @cfg {String} html content of element
822 * @cfg {String} well (lg|sm|md) a well, large, small or medium.
823 * @cfg {String} panel (primary|success|info|warning|danger) render as a panel.
824 * @cfg {String} header content of header (for panel)
825 * @cfg {String} footer content of footer (for panel)
826 * @cfg {String} sticky (footer|wrap|push) block to use as footer or body- needs css-bootstrap/sticky-footer.css
827 * @cfg {String} tag (header|aside|section) type of HTML tag.
831 * Create a new Container
832 * @param {Object} config The config object
835 Roo.bootstrap.Container = function(config){
836 Roo.bootstrap.Container.superclass.constructor.call(this, config);
839 Roo.extend(Roo.bootstrap.Container, Roo.bootstrap.Component, {
850 getChildContainer : function() {
856 if (this.panel.length) {
857 return this.el.select('.panel-body',true).first();
864 getAutoCreate : function(){
867 tag : this.tag || 'div',
871 if (this.jumbotron) {
872 cfg.cls = 'jumbotron';
874 // - this is applied by the parent..
876 // cfg.cls = this.cls + '';
879 if (this.sticky.length) {
881 var bd = Roo.get(document.body);
882 if (!bd.hasClass('bootstrap-sticky')) {
883 bd.addClass('bootstrap-sticky');
884 Roo.select('html',true).setStyle('height', '100%');
887 cfg.cls += 'bootstrap-sticky-' + this.sticky;
891 if (this.well.length) {
895 cfg.cls +=' well well-' +this.well;
905 if (this.panel.length) {
906 cfg.cls += ' panel panel-' + this.panel;
908 if (this.header.length) {
911 cls : 'panel-heading',
927 if (this.footer.length) {
929 cls : 'panel-footer',
938 body.html = this.html || cfg.html;
940 if ((!this.cls || !this.cls.length) && (!cfg.cls || !cfg.cls.length)) {
941 cfg.cls = 'container';
958 * @class Roo.bootstrap.Img
959 * @extends Roo.bootstrap.Component
960 * Bootstrap Img class
961 * @cfg {Boolean} imgResponsive false | true
962 * @cfg {String} border rounded | circle | thumbnail
963 * @cfg {String} src image source
964 * @cfg {String} alt image alternative text
965 * @cfg {String} href a tag href
966 * @cfg {String} target (_self|_blank|_parent|_top)target for a href.
970 * @param {Object} config The config object
973 Roo.bootstrap.Img = function(config){
974 Roo.bootstrap.Img.superclass.constructor.call(this, config);
980 * The img click event for the img.
981 * @param {Roo.EventObject} e
987 Roo.extend(Roo.bootstrap.Img, Roo.bootstrap.Component, {
995 getAutoCreate : function(){
999 cls: (this.imgResponsive) ? 'img-responsive' : '',
1003 cfg.html = this.html || cfg.html;
1005 cfg.src = this.src || cfg.src;
1007 if (['rounded','circle','thumbnail'].indexOf(this.border)>-1) {
1008 cfg.cls += ' img-' + this.border;
1025 a.target = this.target;
1031 return (this.href) ? a : cfg;
1034 initEvents: function() {
1037 this.el.on('click', this.onClick, this);
1041 onClick : function(e)
1043 Roo.log('img onclick');
1044 this.fireEvent('click', this, e);
1058 * @class Roo.bootstrap.Link
1059 * @extends Roo.bootstrap.Component
1060 * Bootstrap Link Class
1061 * @cfg {String} alt image alternative text
1062 * @cfg {String} href a tag href
1063 * @cfg {String} target (_self|_blank|_parent|_top) target for a href.
1064 * @cfg {String} html the content of the link.
1068 * Create a new Input
1069 * @param {Object} config The config object
1072 Roo.bootstrap.Link = function(config){
1073 Roo.bootstrap.Link.superclass.constructor.call(this, config);
1079 * The img click event for the img.
1080 * @param {Roo.EventObject} e
1086 Roo.extend(Roo.bootstrap.Link, Roo.bootstrap.Component, {
1091 getAutoCreate : function(){
1095 html : this.html || 'html-missing'
1102 cfg.href = this.href || '#';
1104 cfg.target = this.target;
1110 initEvents: function() {
1113 this.el.on('click', this.onClick, this);
1117 onClick : function(e)
1119 //Roo.log('img onclick');
1120 this.fireEvent('click', this, e);
1133 * @class Roo.bootstrap.Header
1134 * @extends Roo.bootstrap.Component
1135 * Bootstrap Header class
1136 * @cfg {String} html content of header
1137 * @cfg {Number} level (1|2|3|4|5|6) default 1
1140 * Create a new Header
1141 * @param {Object} config The config object
1145 Roo.bootstrap.Header = function(config){
1146 Roo.bootstrap.Header.superclass.constructor.call(this, config);
1149 Roo.extend(Roo.bootstrap.Header, Roo.bootstrap.Component, {
1157 getAutoCreate : function(){
1160 tag: 'h' + (1 *this.level),
1161 html: this.html || 'fill in html'
1173 * Ext JS Library 1.1.1
1174 * Copyright(c) 2006-2007, Ext JS, LLC.
1176 * Originally Released Under LGPL - original licence link has changed is not relivant.
1179 * <script type="text/javascript">
1183 * @class Roo.bootstrap.MenuMgr
1184 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
1187 Roo.bootstrap.MenuMgr = function(){
1188 var menus, active, groups = {}, attached = false, lastShow = new Date();
1190 // private - called when first menu is created
1193 active = new Roo.util.MixedCollection();
1194 Roo.get(document).addKeyListener(27, function(){
1195 if(active.length > 0){
1203 if(active && active.length > 0){
1204 var c = active.clone();
1214 if(active.length < 1){
1215 Roo.get(document).un("mouseup", onMouseDown);
1223 var last = active.last();
1224 lastShow = new Date();
1227 Roo.get(document).on("mouseup", onMouseDown);
1232 //m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
1233 m.parentMenu.activeChild = m;
1234 }else if(last && last.isVisible()){
1235 //m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
1240 function onBeforeHide(m){
1242 m.activeChild.hide();
1244 if(m.autoHideTimer){
1245 clearTimeout(m.autoHideTimer);
1246 delete m.autoHideTimer;
1251 function onBeforeShow(m){
1252 var pm = m.parentMenu;
1253 if(!pm && !m.allowOtherMenus){
1255 }else if(pm && pm.activeChild && active != m){
1256 pm.activeChild.hide();
1261 function onMouseDown(e){
1262 Roo.log("on MouseDown");
1263 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
1271 function onBeforeCheck(mi, state){
1273 var g = groups[mi.group];
1274 for(var i = 0, l = g.length; i < l; i++){
1276 g[i].setChecked(false);
1285 * Hides all menus that are currently visible
1287 hideAll : function(){
1292 register : function(menu){
1296 menus[menu.id] = menu;
1297 menu.on("beforehide", onBeforeHide);
1298 menu.on("hide", onHide);
1299 menu.on("beforeshow", onBeforeShow);
1300 menu.on("show", onShow);
1302 if(g && menu.events["checkchange"]){
1306 groups[g].push(menu);
1307 menu.on("checkchange", onCheck);
1312 * Returns a {@link Roo.menu.Menu} object
1313 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
1314 * be used to generate and return a new Menu instance.
1316 get : function(menu){
1317 if(typeof menu == "string"){ // menu id
1319 }else if(menu.events){ // menu instance
1322 /*else if(typeof menu.length == 'number'){ // array of menu items?
1323 return new Roo.bootstrap.Menu({items:menu});
1324 }else{ // otherwise, must be a config
1325 return new Roo.bootstrap.Menu(menu);
1332 unregister : function(menu){
1333 delete menus[menu.id];
1334 menu.un("beforehide", onBeforeHide);
1335 menu.un("hide", onHide);
1336 menu.un("beforeshow", onBeforeShow);
1337 menu.un("show", onShow);
1339 if(g && menu.events["checkchange"]){
1340 groups[g].remove(menu);
1341 menu.un("checkchange", onCheck);
1346 registerCheckable : function(menuItem){
1347 var g = menuItem.group;
1352 groups[g].push(menuItem);
1353 menuItem.on("beforecheckchange", onBeforeCheck);
1358 unregisterCheckable : function(menuItem){
1359 var g = menuItem.group;
1361 groups[g].remove(menuItem);
1362 menuItem.un("beforecheckchange", onBeforeCheck);
1374 * @class Roo.bootstrap.Menu
1375 * @extends Roo.bootstrap.Component
1376 * Bootstrap Menu class - container for MenuItems
1377 * @cfg {String} type (dropdown|treeview|submenu) type of menu
1381 * @param {Object} config The config object
1385 Roo.bootstrap.Menu = function(config){
1386 Roo.bootstrap.Menu.superclass.constructor.call(this, config);
1387 if (this.registerMenu) {
1388 Roo.bootstrap.MenuMgr.register(this);
1393 * Fires before this menu is displayed
1394 * @param {Roo.menu.Menu} this
1399 * Fires before this menu is hidden
1400 * @param {Roo.menu.Menu} this
1405 * Fires after this menu is displayed
1406 * @param {Roo.menu.Menu} this
1411 * Fires after this menu is hidden
1412 * @param {Roo.menu.Menu} this
1417 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
1418 * @param {Roo.menu.Menu} this
1419 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1420 * @param {Roo.EventObject} e
1425 * Fires when the mouse is hovering over this menu
1426 * @param {Roo.menu.Menu} this
1427 * @param {Roo.EventObject} e
1428 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1433 * Fires when the mouse exits this menu
1434 * @param {Roo.menu.Menu} this
1435 * @param {Roo.EventObject} e
1436 * @param {Roo.menu.Item} menuItem The menu item that was clicked
1441 * Fires when a menu item contained in this menu is clicked
1442 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
1443 * @param {Roo.EventObject} e
1447 this.menuitems = new Roo.util.MixedCollection(false, function(o) { return o.el.id; });
1450 Roo.extend(Roo.bootstrap.Menu, Roo.bootstrap.Component, {
1454 triggerEl : false, // is this set by component builder? -- it should really be fetched from parent()???
1457 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
1459 registerMenu : true,
1461 menuItems :false, // stores the menu items..
1467 getChildContainer : function() {
1471 getAutoCreate : function(){
1473 //if (['right'].indexOf(this.align)!==-1) {
1474 // cfg.cn[1].cls += ' pull-right'
1480 cls : 'dropdown-menu' ,
1481 style : 'z-index:1000'
1485 if (this.type === 'submenu') {
1486 cfg.cls = 'submenu active';
1488 if (this.type === 'treeview') {
1489 cfg.cls = 'treeview-menu';
1494 initEvents : function() {
1496 // Roo.log("ADD event");
1497 // Roo.log(this.triggerEl.dom);
1498 this.triggerEl.on('click', this.onTriggerPress, this);
1499 this.triggerEl.addClass('dropdown-toggle');
1500 this.el.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
1502 this.el.on("mouseover", this.onMouseOver, this);
1503 this.el.on("mouseout", this.onMouseOut, this);
1507 findTargetItem : function(e){
1508 var t = e.getTarget(".dropdown-menu-item", this.el, true);
1512 //Roo.log(t); Roo.log(t.id);
1514 //Roo.log(this.menuitems);
1515 return this.menuitems.get(t.id);
1517 //return this.items.get(t.menuItemId);
1522 onClick : function(e){
1523 Roo.log("menu.onClick");
1524 var t = this.findTargetItem(e);
1530 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
1531 if(t == this.activeItem && t.shouldDeactivate(e)){
1532 this.activeItem.deactivate();
1533 delete this.activeItem;
1537 this.setActiveItem(t, true);
1544 Roo.log('pass click event');
1548 this.fireEvent("click", this, t, e);
1552 onMouseOver : function(e){
1553 var t = this.findTargetItem(e);
1556 // if(t.canActivate && !t.disabled){
1557 // this.setActiveItem(t, true);
1561 this.fireEvent("mouseover", this, e, t);
1563 isVisible : function(){
1564 return !this.hidden;
1566 onMouseOut : function(e){
1567 var t = this.findTargetItem(e);
1570 // if(t == this.activeItem && t.shouldDeactivate(e)){
1571 // this.activeItem.deactivate();
1572 // delete this.activeItem;
1575 this.fireEvent("mouseout", this, e, t);
1580 * Displays this menu relative to another element
1581 * @param {String/HTMLElement/Roo.Element} element The element to align to
1582 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
1583 * the element (defaults to this.defaultAlign)
1584 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1586 show : function(el, pos, parentMenu){
1587 this.parentMenu = parentMenu;
1591 this.fireEvent("beforeshow", this);
1592 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
1595 * Displays this menu at a specific xy position
1596 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
1597 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
1599 showAt : function(xy, parentMenu, /* private: */_e){
1600 this.parentMenu = parentMenu;
1605 this.fireEvent("beforeshow", this);
1607 //xy = this.el.adjustForConstraints(xy);
1609 //this.el.setXY(xy);
1611 this.hideMenuItems();
1612 this.hidden = false;
1613 this.triggerEl.addClass('open');
1615 this.fireEvent("show", this);
1621 this.doFocus.defer(50, this);
1625 doFocus : function(){
1627 this.focusEl.focus();
1632 * Hides this menu and optionally all parent menus
1633 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
1635 hide : function(deep){
1637 this.hideMenuItems();
1638 if(this.el && this.isVisible()){
1639 this.fireEvent("beforehide", this);
1640 if(this.activeItem){
1641 this.activeItem.deactivate();
1642 this.activeItem = null;
1644 this.triggerEl.removeClass('open');;
1646 this.fireEvent("hide", this);
1648 if(deep === true && this.parentMenu){
1649 this.parentMenu.hide(true);
1653 onTriggerPress : function(e)
1656 Roo.log('trigger press');
1657 //Roo.log(e.getTarget());
1658 // Roo.log(this.triggerEl.dom);
1659 if (Roo.get(e.getTarget()).findParent('.dropdown-menu')) {
1662 if (this.isVisible()) {
1666 this.show(this.triggerEl, false, false);
1675 hideMenuItems : function()
1677 //$(backdrop).remove()
1678 Roo.select('.open',true).each(function(aa) {
1680 aa.removeClass('open');
1681 //var parent = getParent($(this))
1682 //var relatedTarget = { relatedTarget: this }
1684 //$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
1685 //if (e.isDefaultPrevented()) return
1686 //$parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)
1689 addxtypeChild : function (tree, cntr) {
1690 var comp= Roo.bootstrap.Menu.superclass.addxtypeChild.call(this, tree, cntr);
1692 this.menuitems.add(comp);
1713 * @class Roo.bootstrap.MenuItem
1714 * @extends Roo.bootstrap.Component
1715 * Bootstrap MenuItem class
1716 * @cfg {String} html the menu label
1717 * @cfg {String} href the link
1718 * @cfg {Boolean} preventDefault (true | false) default true
1722 * Create a new MenuItem
1723 * @param {Object} config The config object
1727 Roo.bootstrap.MenuItem = function(config){
1728 Roo.bootstrap.MenuItem.superclass.constructor.call(this, config);
1733 * The raw click event for the entire grid.
1734 * @param {Roo.EventObject} e
1740 Roo.extend(Roo.bootstrap.MenuItem, Roo.bootstrap.Component, {
1744 preventDefault: true,
1746 getAutoCreate : function(){
1749 cls: 'dropdown-menu-item',
1758 if (this.parent().type == 'treeview') {
1759 cfg.cls = 'treeview-menu';
1762 cfg.cn[0].href = this.href || cfg.cn[0].href ;
1763 cfg.cn[0].html = this.html || cfg.cn[0].html ;
1767 initEvents: function() {
1769 //this.el.select('a').on('click', this.onClick, this);
1772 onClick : function(e)
1774 Roo.log('item on click ');
1775 //if(this.preventDefault){
1776 // e.preventDefault();
1778 //this.parent().hideMenuItems();
1780 this.fireEvent('click', this, e);
1799 * @class Roo.bootstrap.MenuSeparator
1800 * @extends Roo.bootstrap.Component
1801 * Bootstrap MenuSeparator class
1804 * Create a new MenuItem
1805 * @param {Object} config The config object
1809 Roo.bootstrap.MenuSeparator = function(config){
1810 Roo.bootstrap.MenuSeparator.superclass.constructor.call(this, config);
1813 Roo.extend(Roo.bootstrap.MenuSeparator, Roo.bootstrap.Component, {
1815 getAutoCreate : function(){
1830 <div class="modal fade">
1831 <div class="modal-dialog">
1832 <div class="modal-content">
1833 <div class="modal-header">
1834 <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
1835 <h4 class="modal-title">Modal title</h4>
1837 <div class="modal-body">
1838 <p>One fine body…</p>
1840 <div class="modal-footer">
1841 <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
1842 <button type="button" class="btn btn-primary">Save changes</button>
1844 </div><!-- /.modal-content -->
1845 </div><!-- /.modal-dialog -->
1846 </div><!-- /.modal -->
1856 * @class Roo.bootstrap.Modal
1857 * @extends Roo.bootstrap.Component
1858 * Bootstrap Modal class
1859 * @cfg {String} title Title of dialog
1860 * @cfg {Boolean} specificTitle (true|false) default false
1861 * @cfg {Array} buttons Array of buttons or standard button set..
1862 * @cfg {String} buttonPosition (left|right|center) default right
1865 * Create a new Modal Dialog
1866 * @param {Object} config The config object
1869 Roo.bootstrap.Modal = function(config){
1870 Roo.bootstrap.Modal.superclass.constructor.call(this, config);
1875 * The raw btnclick event for the button
1876 * @param {Roo.EventObject} e
1880 this.buttons = this.buttons || [];
1883 Roo.extend(Roo.bootstrap.Modal, Roo.bootstrap.Component, {
1885 title : 'test dialog',
1892 specificTitle: false,
1894 buttonPosition: 'right',
1896 onRender : function(ct, position)
1898 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
1901 var cfg = Roo.apply({}, this.getAutoCreate());
1904 // cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
1906 //if (!cfg.name.length) {
1910 cfg.cls += ' ' + this.cls;
1913 cfg.style = this.style;
1915 this.el = Roo.get(document.body).createChild(cfg, position);
1917 //var type = this.el.dom.type;
1919 if(this.tabIndex !== undefined){
1920 this.el.dom.setAttribute('tabIndex', this.tabIndex);
1925 this.maskEl = Roo.DomHelper.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
1926 this.maskEl.enableDisplayMode("block");
1928 //this.el.addClass("x-dlg-modal");
1930 if (this.buttons.length) {
1931 Roo.each(this.buttons, function(bb) {
1932 b = Roo.apply({}, bb);
1933 b.xns = b.xns || Roo.bootstrap;
1934 b.xtype = b.xtype || 'Button';
1935 if (typeof(b.listeners) == 'undefined') {
1936 b.listeners = { click : this.onButtonClick.createDelegate(this) };
1939 var btn = Roo.factory(b);
1941 btn.onRender(this.el.select('.modal-footer div').first());
1945 // render the children.
1948 if(typeof(this.items) != 'undefined'){
1949 var items = this.items;
1952 for(var i =0;i < items.length;i++) {
1953 nitems.push(this.addxtype(Roo.apply({}, items[i])));
1957 this.items = nitems;
1959 this.body = this.el.select('.modal-body',true).first();
1960 this.close = this.el.select('.modal-header .close', true).first();
1961 this.footer = this.el.select('.modal-footer',true).first();
1963 //this.el.addClass([this.fieldClass, this.cls]);
1966 getAutoCreate : function(){
1971 html : this.html || ''
1976 cls : 'modal-title',
1980 if(this.specificTitle){
1986 style : 'display: none',
1989 cls: "modal-dialog",
1992 cls : "modal-content",
1995 cls : 'modal-header',
2007 cls : 'modal-footer',
2011 cls: 'btn-' + this.buttonPosition
2030 getChildContainer : function() {
2032 return this.el.select('.modal-body',true).first();
2035 getButtonContainer : function() {
2036 return this.el.select('.modal-footer div',true).first();
2039 initEvents : function()
2041 this.el.select('.modal-header .close').on('click', this.hide, this);
2043 // this.addxtype(this);
2047 if (!this.rendered) {
2051 this.el.addClass('on');
2052 this.el.removeClass('fade');
2053 this.el.setStyle('display', 'block');
2054 Roo.get(document.body).addClass("x-body-masked");
2055 this.maskEl.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
2057 this.el.setStyle('zIndex', '10001');
2058 this.fireEvent('show', this);
2064 Roo.log('Modal hide?!');
2066 Roo.get(document.body).removeClass("x-body-masked");
2067 this.el.removeClass('on');
2068 this.el.addClass('fade');
2069 this.el.setStyle('display', 'none');
2070 this.fireEvent('hide', this);
2073 addButton : function(str, cb)
2077 var b = Roo.apply({}, { html : str } );
2078 b.xns = b.xns || Roo.bootstrap;
2079 b.xtype = b.xtype || 'Button';
2080 if (typeof(b.listeners) == 'undefined') {
2081 b.listeners = { click : cb.createDelegate(this) };
2084 var btn = Roo.factory(b);
2086 btn.onRender(this.el.select('.modal-footer div').first());
2092 setDefaultButton : function(btn)
2094 //this.el.select('.modal-footer').()
2096 resizeTo: function(w,h)
2100 setContentSize : function(w, h)
2104 onButtonClick: function(btn,e)
2107 this.fireEvent('btnclick', btn.name, e);
2109 setTitle: function(str) {
2110 this.el.select('.modal-title',true).first().dom.innerHTML = str;
2116 Roo.apply(Roo.bootstrap.Modal, {
2118 * Button config that displays a single OK button
2127 * Button config that displays Yes and No buttons
2143 * Button config that displays OK and Cancel buttons
2158 * Button config that displays Yes, No and Cancel buttons
2180 * messagebox - can be used as a replace
2184 * @class Roo.MessageBox
2185 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
2189 Roo.Msg.alert('Status', 'Changes saved successfully.');
2191 // Prompt for user data:
2192 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
2194 // process text value...
2198 // Show a dialog using config options:
2200 title:'Save Changes?',
2201 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
2202 buttons: Roo.Msg.YESNOCANCEL,
2209 Roo.bootstrap.MessageBox = function(){
2210 var dlg, opt, mask, waitTimer;
2211 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
2212 var buttons, activeTextEl, bwidth;
2216 var handleButton = function(button){
2218 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
2222 var handleHide = function(){
2224 dlg.el.removeClass(opt.cls);
2227 // Roo.TaskMgr.stop(waitTimer);
2228 // waitTimer = null;
2233 var updateButtons = function(b){
2236 buttons["ok"].hide();
2237 buttons["cancel"].hide();
2238 buttons["yes"].hide();
2239 buttons["no"].hide();
2240 //dlg.footer.dom.style.display = 'none';
2243 dlg.footer.dom.style.display = '';
2244 for(var k in buttons){
2245 if(typeof buttons[k] != "function"){
2248 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.bootstrap.MessageBox.buttonText[k]);
2249 width += buttons[k].el.getWidth()+15;
2259 var handleEsc = function(d, k, e){
2260 if(opt && opt.closable !== false){
2270 * Returns a reference to the underlying {@link Roo.BasicDialog} element
2271 * @return {Roo.BasicDialog} The BasicDialog element
2273 getDialog : function(){
2275 dlg = new Roo.bootstrap.Modal( {
2278 //constraintoviewport:false,
2280 //collapsible : false,
2285 //buttonAlign:"center",
2286 closeClick : function(){
2287 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
2290 handleButton("cancel");
2295 dlg.on("hide", handleHide);
2297 //dlg.addKeyListener(27, handleEsc);
2299 this.buttons = buttons;
2300 var bt = this.buttonText;
2301 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
2302 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
2303 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
2304 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
2306 bodyEl = dlg.body.createChild({
2308 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" />' +
2309 '<textarea class="roo-mb-textarea"></textarea>' +
2310 '<div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
2312 msgEl = bodyEl.dom.firstChild;
2313 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
2314 textboxEl.enableDisplayMode();
2315 textboxEl.addKeyListener([10,13], function(){
2316 if(dlg.isVisible() && opt && opt.buttons){
2319 }else if(opt.buttons.yes){
2320 handleButton("yes");
2324 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
2325 textareaEl.enableDisplayMode();
2326 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
2327 progressEl.enableDisplayMode();
2328 var pf = progressEl.dom.firstChild;
2330 pp = Roo.get(pf.firstChild);
2331 pp.setHeight(pf.offsetHeight);
2339 * Updates the message box body text
2340 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
2341 * the XHTML-compliant non-breaking space character '&#160;')
2342 * @return {Roo.MessageBox} This message box
2344 updateText : function(text){
2345 if(!dlg.isVisible() && !opt.width){
2346 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
2348 msgEl.innerHTML = text || ' ';
2350 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
2351 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
2353 Math.min(opt.width || cw , this.maxWidth),
2354 Math.max(opt.minWidth || this.minWidth, bwidth)
2357 activeTextEl.setWidth(w);
2359 if(dlg.isVisible()){
2360 dlg.fixedcenter = false;
2362 // to big, make it scroll. = But as usual stupid IE does not support
2365 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
2366 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
2367 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
2369 bodyEl.dom.style.height = '';
2370 bodyEl.dom.style.overflowY = '';
2373 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
2375 bodyEl.dom.style.overflowX = '';
2378 dlg.setContentSize(w, bodyEl.getHeight());
2379 if(dlg.isVisible()){
2380 dlg.fixedcenter = true;
2386 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
2387 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
2388 * @param {Number} value Any number between 0 and 1 (e.g., .5)
2389 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
2390 * @return {Roo.MessageBox} This message box
2392 updateProgress : function(value, text){
2394 this.updateText(text);
2396 if (pp) { // weird bug on my firefox - for some reason this is not defined
2397 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
2403 * Returns true if the message box is currently displayed
2404 * @return {Boolean} True if the message box is visible, else false
2406 isVisible : function(){
2407 return dlg && dlg.isVisible();
2411 * Hides the message box if it is displayed
2414 if(this.isVisible()){
2420 * Displays a new message box, or reinitializes an existing message box, based on the config options
2421 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
2422 * The following config object properties are supported:
2424 Property Type Description
2425 ---------- --------------- ------------------------------------------------------------------------------------
2426 animEl String/Element An id or Element from which the message box should animate as it opens and
2427 closes (defaults to undefined)
2428 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
2429 cancel:'Bar'}), or false to not show any buttons (defaults to false)
2430 closable Boolean False to hide the top-right close button (defaults to true). Note that
2431 progress and wait dialogs will ignore this property and always hide the
2432 close button as they can only be closed programmatically.
2433 cls String A custom CSS class to apply to the message box element
2434 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
2435 displayed (defaults to 75)
2436 fn Function A callback function to execute after closing the dialog. The arguments to the
2437 function will be btn (the name of the button that was clicked, if applicable,
2438 e.g. "ok"), and text (the value of the active text field, if applicable).
2439 Progress and wait dialogs will ignore this option since they do not respond to
2440 user actions and can only be closed programmatically, so any required function
2441 should be called by the same code after it closes the dialog.
2442 icon String A CSS class that provides a background image to be used as an icon for
2443 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
2444 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
2445 minWidth Number The minimum width in pixels of the message box (defaults to 100)
2446 modal Boolean False to allow user interaction with the page while the message box is
2447 displayed (defaults to true)
2448 msg String A string that will replace the existing message box body text (defaults
2449 to the XHTML-compliant non-breaking space character ' ')
2450 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
2451 progress Boolean True to display a progress bar (defaults to false)
2452 progressText String The text to display inside the progress bar if progress = true (defaults to '')
2453 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
2454 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
2455 title String The title text
2456 value String The string value to set into the active textbox element if displayed
2457 wait Boolean True to display a progress bar (defaults to false)
2458 width Number The width of the dialog in pixels
2465 msg: 'Please enter your address:',
2467 buttons: Roo.MessageBox.OKCANCEL,
2470 animEl: 'addAddressBtn'
2473 * @param {Object} config Configuration options
2474 * @return {Roo.MessageBox} This message box
2476 show : function(options)
2479 // this causes nightmares if you show one dialog after another
2480 // especially on callbacks..
2482 if(this.isVisible()){
2485 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
2486 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
2487 Roo.log("New Dialog Message:" + options.msg )
2488 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
2489 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
2492 var d = this.getDialog();
2494 d.setTitle(opt.title || " ");
2495 d.close.setDisplayed(opt.closable !== false);
2496 activeTextEl = textboxEl;
2497 opt.prompt = opt.prompt || (opt.multiline ? true : false);
2502 textareaEl.setHeight(typeof opt.multiline == "number" ?
2503 opt.multiline : this.defaultTextHeight);
2504 activeTextEl = textareaEl;
2513 progressEl.setDisplayed(opt.progress === true);
2514 this.updateProgress(0);
2515 activeTextEl.dom.value = opt.value || "";
2517 dlg.setDefaultButton(activeTextEl);
2519 var bs = opt.buttons;
2523 }else if(bs && bs.yes){
2524 db = buttons["yes"];
2526 dlg.setDefaultButton(db);
2528 bwidth = updateButtons(opt.buttons);
2529 this.updateText(opt.msg);
2531 d.el.addClass(opt.cls);
2533 d.proxyDrag = opt.proxyDrag === true;
2534 d.modal = opt.modal !== false;
2535 d.mask = opt.modal !== false ? mask : false;
2537 // force it to the end of the z-index stack so it gets a cursor in FF
2538 document.body.appendChild(dlg.el.dom);
2539 d.animateTarget = null;
2540 d.show(options.animEl);
2546 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
2547 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
2548 * and closing the message box when the process is complete.
2549 * @param {String} title The title bar text
2550 * @param {String} msg The message box body text
2551 * @return {Roo.MessageBox} This message box
2553 progress : function(title, msg){
2560 minWidth: this.minProgressWidth,
2567 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
2568 * If a callback function is passed it will be called after the user clicks the button, and the
2569 * id of the button that was clicked will be passed as the only parameter to the callback
2570 * (could also be the top-right close button).
2571 * @param {String} title The title bar text
2572 * @param {String} msg The message box body text
2573 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2574 * @param {Object} scope (optional) The scope of the callback function
2575 * @return {Roo.MessageBox} This message box
2577 alert : function(title, msg, fn, scope){
2590 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
2591 * interaction while waiting for a long-running process to complete that does not have defined intervals.
2592 * You are responsible for closing the message box when the process is complete.
2593 * @param {String} msg The message box body text
2594 * @param {String} title (optional) The title bar text
2595 * @return {Roo.MessageBox} This message box
2597 wait : function(msg, title){
2608 waitTimer = Roo.TaskMgr.start({
2610 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
2618 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
2619 * If a callback function is passed it will be called after the user clicks either button, and the id of the
2620 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
2621 * @param {String} title The title bar text
2622 * @param {String} msg The message box body text
2623 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2624 * @param {Object} scope (optional) The scope of the callback function
2625 * @return {Roo.MessageBox} This message box
2627 confirm : function(title, msg, fn, scope){
2631 buttons: this.YESNO,
2640 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
2641 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
2642 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
2643 * (could also be the top-right close button) and the text that was entered will be passed as the two
2644 * parameters to the callback.
2645 * @param {String} title The title bar text
2646 * @param {String} msg The message box body text
2647 * @param {Function} fn (optional) The callback function invoked after the message box is closed
2648 * @param {Object} scope (optional) The scope of the callback function
2649 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
2650 * property, or the height in pixels to create the textbox (defaults to false / single-line)
2651 * @return {Roo.MessageBox} This message box
2653 prompt : function(title, msg, fn, scope, multiline){
2657 buttons: this.OKCANCEL,
2662 multiline: multiline,
2669 * Button config that displays a single OK button
2674 * Button config that displays Yes and No buttons
2677 YESNO : {yes:true, no:true},
2679 * Button config that displays OK and Cancel buttons
2682 OKCANCEL : {ok:true, cancel:true},
2684 * Button config that displays Yes, No and Cancel buttons
2687 YESNOCANCEL : {yes:true, no:true, cancel:true},
2690 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
2693 defaultTextHeight : 75,
2695 * The maximum width in pixels of the message box (defaults to 600)
2700 * The minimum width in pixels of the message box (defaults to 100)
2705 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
2706 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
2709 minProgressWidth : 250,
2711 * An object containing the default button text strings that can be overriden for localized language support.
2712 * Supported properties are: ok, cancel, yes and no.
2713 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
2726 * Shorthand for {@link Roo.MessageBox}
2728 Roo.MessageBox = Roo.MessageBox || Roo.bootstrap.MessageBox
2729 Roo.Msg = Roo.Msg || Roo.MessageBox;
2738 * @class Roo.bootstrap.Navbar
2739 * @extends Roo.bootstrap.Component
2740 * Bootstrap Navbar class
2743 * Create a new Navbar
2744 * @param {Object} config The config object
2748 Roo.bootstrap.Navbar = function(config){
2749 Roo.bootstrap.Navbar.superclass.constructor.call(this, config);
2753 Roo.extend(Roo.bootstrap.Navbar, Roo.bootstrap.Component, {
2762 getAutoCreate : function(){
2765 throw { message : "nav bar is now a abstract base class - use NavSimplebar / NavHeaderbar / NavSidebar etc..."};
2769 initEvents :function ()
2771 //Roo.log(this.el.select('.navbar-toggle',true));
2772 this.el.select('.navbar-toggle',true).on('click', function() {
2773 // Roo.log('click');
2774 this.el.select('.navbar-collapse',true).toggleClass('in');
2782 this.maskEl = Roo.DomHelper.append(this.el, mark, true);
2784 var size = this.el.getSize();
2785 this.maskEl.setSize(size.width, size.height);
2786 this.maskEl.enableDisplayMode("block");
2795 getChildContainer : function()
2797 if (this.el.select('.collapse').getCount()) {
2798 return this.el.select('.collapse',true).first();
2830 * @class Roo.bootstrap.NavSimplebar
2831 * @extends Roo.bootstrap.Navbar
2832 * Bootstrap Sidebar class
2834 * @cfg {Boolean} inverse is inverted color
2836 * @cfg {String} type (nav | pills | tabs)
2837 * @cfg {Boolean} arrangement stacked | justified
2838 * @cfg {String} align (left | right) alignment
2840 * @cfg {Boolean} main (true|false) main nav bar? default false
2841 * @cfg {Boolean} loadMask (true|false) loadMask on the bar
2843 * @cfg {String} tag (header|footer|nav|div) default is nav
2849 * Create a new Sidebar
2850 * @param {Object} config The config object
2854 Roo.bootstrap.NavSimplebar = function(config){
2855 Roo.bootstrap.NavSimplebar.superclass.constructor.call(this, config);
2858 Roo.extend(Roo.bootstrap.NavSimplebar, Roo.bootstrap.Navbar, {
2874 getAutoCreate : function(){
2878 tag : this.tag || 'div',
2891 this.type = this.type || 'nav';
2892 if (['tabs','pills'].indexOf(this.type)!==-1) {
2893 cfg.cn[0].cls += ' nav-' + this.type
2897 if (this.type!=='nav') {
2898 Roo.log('nav type must be nav/tabs/pills')
2900 cfg.cn[0].cls += ' navbar-nav'
2906 if (['stacked','justified'].indexOf(this.arrangement)!==-1) {
2907 cfg.cn[0].cls += ' nav-' + this.arrangement;
2911 if (this.align === 'right') {
2912 cfg.cn[0].cls += ' navbar-right';
2916 cfg.cls += ' navbar-inverse';
2943 * @class Roo.bootstrap.NavHeaderbar
2944 * @extends Roo.bootstrap.NavSimplebar
2945 * Bootstrap Sidebar class
2947 * @cfg {String} brand what is brand
2948 * @cfg {String} position (fixed-top|fixed-bottom|static-top) position
2949 * @cfg {String} brand_href href of the brand
2952 * Create a new Sidebar
2953 * @param {Object} config The config object
2957 Roo.bootstrap.NavHeaderbar = function(config){
2958 Roo.bootstrap.NavHeaderbar.superclass.constructor.call(this, config);
2961 Roo.extend(Roo.bootstrap.NavHeaderbar, Roo.bootstrap.NavSimplebar, {
2968 getAutoCreate : function(){
2973 tag: this.nav || 'nav',
2979 cls: 'navbar-header',
2984 cls: 'navbar-toggle',
2985 'data-toggle': 'collapse',
2990 html: 'Toggle navigation'
3010 cls: 'collapse navbar-collapse'
3015 cfg.cls += this.inverse ? ' navbar-inverse' : ' navbar-default';
3017 if (['fixed-top','fixed-bottom','static-top'].indexOf(this.position)>-1) {
3018 cfg.cls += ' navbar-' + this.position;
3020 // tag can override this..
3022 cfg.tag = this.tag || (this.position == 'fixed-bottom' ? 'footer' : 'header');
3025 if (this.brand !== '') {
3028 href: this.brand_href ? this.brand_href : '#',
3029 cls: 'navbar-brand',
3037 cfg.cls += ' main-nav';
3062 * @class Roo.bootstrap.NavSidebar
3063 * @extends Roo.bootstrap.Navbar
3064 * Bootstrap Sidebar class
3067 * Create a new Sidebar
3068 * @param {Object} config The config object
3072 Roo.bootstrap.NavSidebar = function(config){
3073 Roo.bootstrap.NavSidebar.superclass.constructor.call(this, config);
3076 Roo.extend(Roo.bootstrap.NavSidebar, Roo.bootstrap.Navbar, {
3078 sidebar : true, // used by Navbar Item and NavbarGroup at present...
3080 getAutoCreate : function(){
3085 cls: 'sidebar sidebar-nav'
3107 * @class Roo.bootstrap.NavGroup
3108 * @extends Roo.bootstrap.Component
3109 * Bootstrap NavGroup class
3110 * @cfg {String} align left | right
3111 * @cfg {Boolean} inverse false | true
3112 * @cfg {String} type (nav|pills|tab) default nav
3113 * @cfg {String} navId - reference Id for navbar.
3117 * Create a new nav group
3118 * @param {Object} config The config object
3121 Roo.bootstrap.NavGroup = function(config){
3122 Roo.bootstrap.NavGroup.superclass.constructor.call(this, config);
3124 Roo.bootstrap.NavGroup.register(this);
3128 * Fires when the active item changes
3129 * @param {Roo.bootstrap.NavGroup} this
3130 * @param {Roo.bootstrap.Navbar.Item} item The item selected
3131 * @param {Roo.bootstrap.Navbar.Item} item The previously selected item
3138 Roo.extend(Roo.bootstrap.NavGroup, Roo.bootstrap.Component, {
3149 getAutoCreate : function()
3151 var cfg = Roo.apply({}, Roo.bootstrap.NavGroup.superclass.getAutoCreate.call(this));
3158 if (['tabs','pills'].indexOf(this.type)!==-1) {
3159 cfg.cls += ' nav-' + this.type
3161 if (this.type!=='nav') {
3162 Roo.log('nav type must be nav/tabs/pills')
3164 cfg.cls += ' navbar-nav'
3167 if (this.parent().sidebar) {
3170 cls: 'dashboard-menu sidebar-menu'
3176 if (this.form === true) {
3182 if (this.align === 'right') {
3183 cfg.cls += ' navbar-right';
3185 cfg.cls += ' navbar-left';
3189 if (this.align === 'right') {
3190 cfg.cls += ' navbar-right';
3194 cfg.cls += ' navbar-inverse';
3202 setActiveItem : function(item)
3205 Roo.each(this.navItems, function(v){
3210 v.setActive(false, true);
3217 item.setActive(true, true);
3218 this.fireEvent('changed', this, item, prev);
3224 register : function(item)
3226 this.navItems.push( item);
3227 item.navId = this.navId;
3230 getNavItem: function(tabId)
3233 Roo.each(this.navItems, function(e) {
3234 if (e.tabId == tabId) {
3246 Roo.apply(Roo.bootstrap.NavGroup, {
3250 register : function(navgrp)
3252 this.groups[navgrp.navId] = navgrp;
3255 get: function(navId) {
3256 return this.groups[navId];
3271 * @class Roo.bootstrap.Navbar.Item
3272 * @extends Roo.bootstrap.Component
3273 * Bootstrap Navbar.Button class
3274 * @cfg {String} href link to
3275 * @cfg {String} html content of button
3276 * @cfg {String} badge text inside badge
3277 * @cfg {String} glyphicon name of glyphicon
3278 * @cfg {String} icon name of font awesome icon
3279 * @cfg {Boolean} active Is item active
3280 * @cfg {Boolean} preventDefault (true | false) default false
3281 * @cfg {String} tabId the tab that this item activates.
3284 * Create a new Navbar Button
3285 * @param {Object} config The config object
3287 Roo.bootstrap.Navbar.Item = function(config){
3288 Roo.bootstrap.Navbar.Item.superclass.constructor.call(this, config);
3293 * The raw click event for the entire grid.
3294 * @param {Roo.EventObject} e
3299 * Fires when the active item active state changes
3300 * @param {Roo.bootstrap.Navbar.Item} this
3301 * @param {boolean} state the new state
3309 Roo.extend(Roo.bootstrap.Navbar.Item, Roo.bootstrap.Component, {
3317 preventDefault : false,
3320 getAutoCreate : function(){
3322 var cfg = Roo.apply({}, Roo.bootstrap.Navbar.Item.superclass.getAutoCreate.call(this));
3324 if (this.parent().parent().sidebar === true) {
3337 cfg.cn[0].html = this.html;
3341 this.cls += ' active';
3345 cfg.cn[0].cls += ' dropdown-toggle';
3346 cfg.cn[0].html = (cfg.cn[0].html || this.html) + '<span class="glyphicon glyphicon-chevron-down"></span>';
3350 cfg.cn[0].tag = 'a',
3351 cfg.cn[0].href = this.href;
3354 if (this.glyphicon) {
3355 cfg.cn[0].html = '<i class="glyphicon glyphicon-'+this.glyphicon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3359 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3371 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3381 if (this.glyphicon) {
3382 if(cfg.html){cfg.html = ' ' + this.html};
3386 cls: 'glyphicon glyphicon-' + this.glyphicon
3391 cfg.cn[0].html = this.html || cfg.cn[0].html ;
3396 cfg.cn[0].html += " <span class='caret'></span>";
3397 //}else if (!this.href) {
3398 // cfg.cn[0].tag='p';
3399 // cfg.cn[0].cls='navbar-text';
3402 cfg.cn[0].href=this.href||'#';
3403 cfg.cn[0].html=this.html;
3406 if (this.badge !== '') {
3409 cfg.cn[0].html + ' ',
3420 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html || this.html + '</span>'
3425 initEvents: function() {
3426 // Roo.log('init events?');
3427 // Roo.log(this.el.dom);
3428 this.el.select('a',true).on('click', this.onClick, this);
3429 // at this point parent should be available..
3430 this.parent().register(this);
3433 onClick : function(e)
3435 if(this.preventDefault){
3439 if(this.fireEvent('click', this, e) === false){
3443 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3444 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3445 this.parent().setActiveItem(this);
3453 isActive: function () {
3456 setActive : function(state, fire)
3458 this.active = state;
3460 this.el.removeClass('active');
3461 } else if (!this.el.hasClass('active')) {
3462 this.el.addClass('active');
3465 this.fireEvent('changed', this, state);
3470 // this should not be here...
3483 * @class Roo.bootstrap.NavItem
3484 * @extends Roo.bootstrap.Component
3485 * Bootstrap Navbar.NavItem class
3486 * @cfg {String} href link to
3487 * @cfg {String} html content of button
3488 * @cfg {String} badge text inside badge
3489 * @cfg {String} badgecls (bg-green|bg-red|bg-yellow)the extra classes for the badge
3490 * @cfg {String} glyphicon name of glyphicon
3491 * @cfg {String} icon name of font awesome icon
3492 * @cfg {Boolean} active Is item active
3493 * @cfg {Boolean} preventDefault (true | false) default false
3494 * @cfg {String} tabId the tab that this item activates.
3497 * Create a new Navbar Item
3498 * @param {Object} config The config object
3500 Roo.bootstrap.NavItem = function(config){
3501 Roo.bootstrap.NavItem.superclass.constructor.call(this, config);
3506 * The raw click event for the entire grid.
3507 * @param {Roo.EventObject} e
3512 * Fires when the active item active state changes
3513 * @param {Roo.bootstrap.NavItem} this
3514 * @param {boolean} state the new state
3522 Roo.extend(Roo.bootstrap.NavItem, Roo.bootstrap.Component, {
3530 preventDefault : false,
3533 getAutoCreate : function(){
3541 href : this.href || "#",
3542 html: this.html || ''
3548 cfg.cls = typeof(cfg.cls) == 'undefined' ? 'active' : cfg.cls + ' active';
3551 // glyphicon and icon go before content..
3552 if (this.glyphicon || this.icon) {
3554 cfg.cn[0].html = '<i class="'+this.icon+'"></i><span>' + cfg.cn[0].html + '</span>'
3556 cfg.cn[0].html = '<span class="glyphicon glyphicon-' + this.glyphicon + '"></span>' + cfg.cn[0].html;
3564 cfg.cn[0].html += " <span class='caret'></span>";
3568 if (this.badge !== '') {
3570 cfg.cn[0].html += ' <span class="badge">' + this.badge + '</span>';
3577 initEvents: function() {
3578 // Roo.log('init events?');
3579 // Roo.log(this.el.dom);
3580 this.el.select('a',true).on('click', this.onClick, this);
3581 // at this point parent should be available..
3582 this.parent().register(this);
3585 onClick : function(e)
3587 if(this.preventDefault){
3591 if(this.fireEvent('click', this, e) === false){
3595 if (['tabs','pills'].indexOf(this.parent().type)!==-1) {
3596 if (typeof(this.parent().setActiveItem) !== 'undefined') {
3597 this.parent().setActiveItem(this);
3605 isActive: function () {
3608 setActive : function(state, fire)
3610 this.active = state;
3612 this.el.removeClass('active');
3613 } else if (!this.el.hasClass('active')) {
3614 this.el.addClass('active');
3617 this.fireEvent('changed', this, state);
3622 // this should not be here...
3633 * <span> icon </span>
3634 * <span> text </span>
3635 * <span>badge </span>
3639 * @class Roo.bootstrap.NavSidebarItem
3640 * @extends Roo.bootstrap.Component
3641 * Bootstrap Navbar.NavSidebarItem class
3643 * Create a new Navbar Button
3644 * @param {Object} config The config object
3646 Roo.bootstrap.NavSidebarItem = function(config){
3647 Roo.bootstrap.NavSidebarItem.superclass.constructor.call(this, config);
3652 * The raw click event for the entire grid.
3653 * @param {Roo.EventObject} e
3658 * Fires when the active item active state changes
3659 * @param {Roo.bootstrap.Navbar.Item} this
3660 * @param {boolean} state the new state
3668 Roo.extend(Roo.bootstrap.NavSidebarItem, Roo.bootstrap.NavItem, {
3671 getAutoCreate : function(){
3676 href : this.href || '#',
3688 html : this.html || ''
3693 cfg.cls += ' active';
3697 if (this.glyphicon || this.icon) {
3698 var c = this.glyphicon ? ('glyphicon glyphicon-'+this.glyphicon) : this.icon;
3699 a.cn.push({ tag : 'i', cls : c }) ;
3704 if (this.badge !== '') {
3705 a.cn.push({ tag: 'span', cls : 'badge pull-right ' + (this.badgecls || ''), html: this.badge });
3709 a.cn.push({ tag : 'i', cls : 'glyphicon glyphicon-chevron-down pull-right'});
3710 a.cls += 'dropdown-toggle treeview' ;
3734 * @class Roo.bootstrap.Row
3735 * @extends Roo.bootstrap.Component
3736 * Bootstrap Row class (contains columns...)
3740 * @param {Object} config The config object
3743 Roo.bootstrap.Row = function(config){
3744 Roo.bootstrap.Row.superclass.constructor.call(this, config);
3747 Roo.extend(Roo.bootstrap.Row, Roo.bootstrap.Component, {
3749 getAutoCreate : function(){
3768 * @class Roo.bootstrap.Element
3769 * @extends Roo.bootstrap.Component
3770 * Bootstrap Element class
3771 * @cfg {String} html contents of the element
3772 * @cfg {String} tag tag of the element
3773 * @cfg {String} cls class of the element
3776 * Create a new Element
3777 * @param {Object} config The config object
3780 Roo.bootstrap.Element = function(config){
3781 Roo.bootstrap.Element.superclass.constructor.call(this, config);
3784 Roo.extend(Roo.bootstrap.Element, Roo.bootstrap.Component, {
3791 getAutoCreate : function(){
3816 * @class Roo.bootstrap.Pagination
3817 * @extends Roo.bootstrap.Component
3818 * Bootstrap Pagination class
3819 * @cfg {String} size xs | sm | md | lg
3820 * @cfg {Boolean} inverse false | true
3823 * Create a new Pagination
3824 * @param {Object} config The config object
3827 Roo.bootstrap.Pagination = function(config){
3828 Roo.bootstrap.Pagination.superclass.constructor.call(this, config);
3831 Roo.extend(Roo.bootstrap.Pagination, Roo.bootstrap.Component, {
3837 getAutoCreate : function(){
3843 cfg.cls += ' inverse';
3849 cfg.cls += " " + this.cls;
3867 * @class Roo.bootstrap.PaginationItem
3868 * @extends Roo.bootstrap.Component
3869 * Bootstrap PaginationItem class
3870 * @cfg {String} html text
3871 * @cfg {String} href the link
3872 * @cfg {Boolean} preventDefault (true | false) default true
3873 * @cfg {Boolean} active (true | false) default false
3877 * Create a new PaginationItem
3878 * @param {Object} config The config object
3882 Roo.bootstrap.PaginationItem = function(config){
3883 Roo.bootstrap.PaginationItem.superclass.constructor.call(this, config);
3888 * The raw click event for the entire grid.
3889 * @param {Roo.EventObject} e
3895 Roo.extend(Roo.bootstrap.PaginationItem, Roo.bootstrap.Component, {
3899 preventDefault: true,
3903 getAutoCreate : function(){
3909 href : this.href ? this.href : '#',
3910 html : this.html ? this.html : ''
3920 cfg.cls = typeof(cfg.cls) !== 'undefined' ? cfg.cls + ' active' : 'active';
3926 initEvents: function() {
3928 this.el.on('click', this.onClick, this);
3931 onClick : function(e)
3933 Roo.log('PaginationItem on click ');
3934 if(this.preventDefault){
3938 this.fireEvent('click', this, e);
3954 * @class Roo.bootstrap.Slider
3955 * @extends Roo.bootstrap.Component
3956 * Bootstrap Slider class
3959 * Create a new Slider
3960 * @param {Object} config The config object
3963 Roo.bootstrap.Slider = function(config){
3964 Roo.bootstrap.Slider.superclass.constructor.call(this, config);
3967 Roo.extend(Roo.bootstrap.Slider, Roo.bootstrap.Component, {
3969 getAutoCreate : function(){
3973 cls: 'slider slider-sample1 vertical-handler ui-slider ui-slider-horizontal ui-widget ui-widget-content ui-corner-all',
3977 cls: 'ui-slider-handle ui-state-default ui-corner-all'
3995 * @class Roo.bootstrap.Table
3996 * @extends Roo.bootstrap.Component
3997 * Bootstrap Table class
3998 * @cfg {String} cls table class
3999 * @cfg {String} align (left|center|right) Specifies the alignment of a table according to surrounding text
4000 * @cfg {String} bgcolor Specifies the background color for a table
4001 * @cfg {Number} border Specifies whether the table cells should have borders or not
4002 * @cfg {Number} cellpadding Specifies the space between the cell wall and the cell content
4003 * @cfg {Number} cellspacing Specifies the space between cells
4004 * @cfg {String} frame Specifies which parts of the outside borders that should be visible
4005 * @cfg {String} rules Specifies which parts of the inside borders that should be visible
4006 * @cfg {String} sortable Specifies that the table should be sortable
4007 * @cfg {String} summary Specifies a summary of the content of a table
4008 * @cfg {Number} width Specifies the width of a table
4010 * @cfg {boolean} striped Should the rows be alternative striped
4011 * @cfg {boolean} bordered Add borders to the table
4012 * @cfg {boolean} hover Add hover highlighting
4013 * @cfg {boolean} condensed Format condensed
4014 * @cfg {boolean} responsive Format condensed
4020 * Create a new Table
4021 * @param {Object} config The config object
4024 Roo.bootstrap.Table = function(config){
4025 Roo.bootstrap.Table.superclass.constructor.call(this, config);
4028 this.selModel = Roo.factory(this.sm, Roo.bootstrap.Table);
4029 this.sm = this.selModel;
4030 this.sm.xmodule = this.xmodule || false;
4032 if (this.cm && typeof(this.cm.config) == 'undefined') {
4033 this.colModel = new Roo.bootstrap.Table.ColumnModel(this.cm);
4034 this.cm = this.colModel;
4035 this.cm.xmodule = this.xmodule || false;
4038 this.store= Roo.factory(this.store, Roo.data);
4039 this.ds = this.store;
4040 this.ds.xmodule = this.xmodule || false;
4045 Roo.extend(Roo.bootstrap.Table, Roo.bootstrap.Component, {
4067 getAutoCreate : function(){
4068 var cfg = Roo.apply({}, Roo.bootstrap.Table.superclass.getAutoCreate.call(this));
4077 cfg.cls += ' table-striped';
4080 cfg.cls += ' table-hover';
4082 if (this.bordered) {
4083 cfg.cls += ' table-bordered';
4085 if (this.condensed) {
4086 cfg.cls += ' table-condensed';
4088 if (this.responsive) {
4089 cfg.cls += ' table-responsive';
4096 cfg.cls+= ' ' +this.cls;
4099 // this lot should be simplifed...
4102 cfg.align=this.align;
4105 cfg.bgcolor=this.bgcolor;
4108 cfg.border=this.border;
4110 if (this.cellpadding) {
4111 cfg.cellpadding=this.cellpadding;
4113 if (this.cellspacing) {
4114 cfg.cellspacing=this.cellspacing;
4117 cfg.frame=this.frame;
4120 cfg.rules=this.rules;
4122 if (this.sortable) {
4123 cfg.sortable=this.sortable;
4126 cfg.summary=this.summary;
4129 cfg.width=this.width;
4132 if(this.store || this.cm){
4133 cfg.cn.push(this.renderHeader());
4134 cfg.cn.push(this.renderBody());
4135 cfg.cn.push(this.renderFooter());
4137 cfg.cls+= ' TableGrid';
4143 // initTableGrid : function()
4152 // var cm = this.cm;
4154 // for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4157 // html: cm.getColumnHeader(i)
4161 // cfg.push(header);
4168 initEvents : function()
4170 if(!this.store || !this.cm){
4174 Roo.log('initEvents with ds!!!!');
4178 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4179 e.on('click', _this.sort, _this);
4181 // this.maskEl = Roo.DomHelper.append(this.el.select('.TableGrid', true).first(), {tag: "div", cls:"x-dlg-mask"}, true);
4182 // this.maskEl.enableDisplayMode("block");
4183 // this.maskEl.show();
4185 this.store.on('load', this.onLoad, this);
4186 this.store.on('beforeload', this.onBeforeLoad, this);
4194 sort : function(e,el)
4196 var col = Roo.get(el)
4198 if(!col.hasClass('sortable')){
4202 var sort = col.attr('sort');
4205 if(col.hasClass('glyphicon-arrow-up')){
4209 this.store.sortInfo = {field : sort, direction : dir};
4214 renderHeader : function()
4223 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4225 var config = cm.config[i];
4229 html: cm.getColumnHeader(i)
4232 if(typeof(config.dataIndex) != 'undefined'){
4233 c.sort = config.dataIndex;
4236 if(typeof(config.sortable) != 'undefined' && config.sortable){
4240 if(typeof(config.width) != 'undefined'){
4241 c.style = 'width:' + config.width + 'px';
4250 renderBody : function()
4260 renderFooter : function()
4272 Roo.log('ds onload');
4277 Roo.each(this.el.select('thead th.sortable', true).elements, function(e){
4278 e.removeClass(['glyphicon', 'glyphicon-arrow-up', 'glyphicon-arrow-down']);
4280 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'ASC'){
4281 e.addClass(['glyphicon', 'glyphicon-arrow-up']);
4284 if(e.hasClass('sortable') && e.attr('sort') == _this.store.sortInfo.field && _this.store.sortInfo.direction.toUpperCase() == 'DESC'){
4285 e.addClass(['glyphicon', 'glyphicon-arrow-down']);
4289 var tbody = this.el.select('tbody', true).first();
4293 if(this.store.getCount() > 0){
4294 this.store.data.each(function(d){
4300 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
4301 var renderer = cm.getRenderer(i);
4302 var config = cm.config[i];
4306 if(typeof(renderer) !== 'undefined'){
4307 value = renderer(d.data[cm.getDataIndex(i)], false, d);
4310 if(typeof(value) === 'object'){
4320 html: (typeof(value) === 'object') ? '' : value
4323 if(typeof(config.width) != 'undefined'){
4324 td.style = 'width:' + config.width + 'px';
4331 tbody.createChild(row);
4339 Roo.each(renders, function(r){
4340 _this.renderColumn(r);
4344 // if(this.loadMask){
4345 // this.maskEl.hide();
4349 onBeforeLoad : function()
4351 Roo.log('ds onBeforeLoad');
4355 // if(this.loadMask){
4356 // this.maskEl.show();
4362 this.el.select('tbody', true).first().dom.innerHTML = '';
4365 getSelectionModel : function(){
4367 this.selModel = new Roo.bootstrap.Table.RowSelectionModel();
4369 return this.selModel;
4372 renderColumn : function(r)
4375 r.cfg.render(Roo.get(r.id));
4378 Roo.each(r.cfg.cn, function(c){
4383 _this.renderColumn(child);
4400 * @class Roo.bootstrap.TableCell
4401 * @extends Roo.bootstrap.Component
4402 * Bootstrap TableCell class
4403 * @cfg {String} html cell contain text
4404 * @cfg {String} cls cell class
4405 * @cfg {String} tag cell tag (td|th) default td
4406 * @cfg {String} abbr Specifies an abbreviated version of the content in a cell
4407 * @cfg {String} align Aligns the content in a cell
4408 * @cfg {String} axis Categorizes cells
4409 * @cfg {String} bgcolor Specifies the background color of a cell
4410 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4411 * @cfg {Number} colspan Specifies the number of columns a cell should span
4412 * @cfg {String} headers Specifies one or more header cells a cell is related to
4413 * @cfg {Number} height Sets the height of a cell
4414 * @cfg {String} nowrap Specifies that the content inside a cell should not wrap
4415 * @cfg {Number} rowspan Sets the number of rows a cell should span
4416 * @cfg {String} scope Defines a way to associate header cells and data cells in a table
4417 * @cfg {String} valign Vertical aligns the content in a cell
4418 * @cfg {Number} width Specifies the width of a cell
4421 * Create a new TableCell
4422 * @param {Object} config The config object
4425 Roo.bootstrap.TableCell = function(config){
4426 Roo.bootstrap.TableCell.superclass.constructor.call(this, config);
4429 Roo.extend(Roo.bootstrap.TableCell, Roo.bootstrap.Component, {
4449 getAutoCreate : function(){
4450 var cfg = Roo.apply({}, Roo.bootstrap.TableCell.superclass.getAutoCreate.call(this));
4470 cfg.align=this.align
4476 cfg.bgcolor=this.bgcolor
4479 cfg.charoff=this.charoff
4482 cfg.colspan=this.colspan
4485 cfg.headers=this.headers
4488 cfg.height=this.height
4491 cfg.nowrap=this.nowrap
4494 cfg.rowspan=this.rowspan
4497 cfg.scope=this.scope
4500 cfg.valign=this.valign
4503 cfg.width=this.width
4522 * @class Roo.bootstrap.TableRow
4523 * @extends Roo.bootstrap.Component
4524 * Bootstrap TableRow class
4525 * @cfg {String} cls row class
4526 * @cfg {String} align Aligns the content in a table row
4527 * @cfg {String} bgcolor Specifies a background color for a table row
4528 * @cfg {Number} charoff Sets the number of characters the content will be aligned from the character specified by the char attribute
4529 * @cfg {String} valign Vertical aligns the content in a table row
4532 * Create a new TableRow
4533 * @param {Object} config The config object
4536 Roo.bootstrap.TableRow = function(config){
4537 Roo.bootstrap.TableRow.superclass.constructor.call(this, config);
4540 Roo.extend(Roo.bootstrap.TableRow, Roo.bootstrap.Component, {
4548 getAutoCreate : function(){
4549 var cfg = Roo.apply({}, Roo.bootstrap.TableRow.superclass.getAutoCreate.call(this));
4559 cfg.align = this.align;
4562 cfg.bgcolor = this.bgcolor;
4565 cfg.charoff = this.charoff;
4568 cfg.valign = this.valign;
4586 * @class Roo.bootstrap.TableBody
4587 * @extends Roo.bootstrap.Component
4588 * Bootstrap TableBody class
4589 * @cfg {String} cls element class
4590 * @cfg {String} tag element tag (thead|tbody|tfoot) default tbody
4591 * @cfg {String} align Aligns the content inside the element
4592 * @cfg {Number} charoff Sets the number of characters the content inside the element will be aligned from the character specified by the char attribute
4593 * @cfg {String} valign Vertical aligns the content inside the <tbody> element
4596 * Create a new TableBody
4597 * @param {Object} config The config object
4600 Roo.bootstrap.TableBody = function(config){
4601 Roo.bootstrap.TableBody.superclass.constructor.call(this, config);
4604 Roo.extend(Roo.bootstrap.TableBody, Roo.bootstrap.Component, {
4612 getAutoCreate : function(){
4613 var cfg = Roo.apply({}, Roo.bootstrap.TableBody.superclass.getAutoCreate.call(this));
4627 cfg.align = this.align;
4630 cfg.charoff = this.charoff;
4633 cfg.valign = this.valign;
4640 // initEvents : function()
4647 // this.store = Roo.factory(this.store, Roo.data);
4648 // this.store.on('load', this.onLoad, this);
4650 // this.store.load();
4654 // onLoad: function ()
4656 // this.fireEvent('load', this);
4666 * Ext JS Library 1.1.1
4667 * Copyright(c) 2006-2007, Ext JS, LLC.
4669 * Originally Released Under LGPL - original licence link has changed is not relivant.
4672 * <script type="text/javascript">
4675 // as we use this in bootstrap.
4676 Roo.namespace('Roo.form');
4678 * @class Roo.form.Action
4679 * Internal Class used to handle form actions
4681 * @param {Roo.form.BasicForm} el The form element or its id
4682 * @param {Object} config Configuration options
4687 // define the action interface
4688 Roo.form.Action = function(form, options){
4690 this.options = options || {};
4693 * Client Validation Failed
4696 Roo.form.Action.CLIENT_INVALID = 'client';
4698 * Server Validation Failed
4701 Roo.form.Action.SERVER_INVALID = 'server';
4703 * Connect to Server Failed
4706 Roo.form.Action.CONNECT_FAILURE = 'connect';
4708 * Reading Data from Server Failed
4711 Roo.form.Action.LOAD_FAILURE = 'load';
4713 Roo.form.Action.prototype = {
4715 failureType : undefined,
4716 response : undefined,
4720 run : function(options){
4725 success : function(response){
4730 handleResponse : function(response){
4734 // default connection failure
4735 failure : function(response){
4737 this.response = response;
4738 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4739 this.form.afterAction(this, false);
4742 processResponse : function(response){
4743 this.response = response;
4744 if(!response.responseText){
4747 this.result = this.handleResponse(response);
4751 // utility functions used internally
4752 getUrl : function(appendParams){
4753 var url = this.options.url || this.form.url || this.form.el.dom.action;
4755 var p = this.getParams();
4757 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
4763 getMethod : function(){
4764 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
4767 getParams : function(){
4768 var bp = this.form.baseParams;
4769 var p = this.options.params;
4771 if(typeof p == "object"){
4772 p = Roo.urlEncode(Roo.applyIf(p, bp));
4773 }else if(typeof p == 'string' && bp){
4774 p += '&' + Roo.urlEncode(bp);
4777 p = Roo.urlEncode(bp);
4782 createCallback : function(){
4784 success: this.success,
4785 failure: this.failure,
4787 timeout: (this.form.timeout*1000),
4788 upload: this.form.fileUpload ? this.success : undefined
4793 Roo.form.Action.Submit = function(form, options){
4794 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
4797 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
4800 haveProgress : false,
4801 uploadComplete : false,
4803 // uploadProgress indicator.
4804 uploadProgress : function()
4806 if (!this.form.progressUrl) {
4810 if (!this.haveProgress) {
4811 Roo.MessageBox.progress("Uploading", "Uploading");
4813 if (this.uploadComplete) {
4814 Roo.MessageBox.hide();
4818 this.haveProgress = true;
4820 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
4822 var c = new Roo.data.Connection();
4824 url : this.form.progressUrl,
4829 success : function(req){
4830 //console.log(data);
4834 rdata = Roo.decode(req.responseText)
4836 Roo.log("Invalid data from server..");
4840 if (!rdata || !rdata.success) {
4842 Roo.MessageBox.alert(Roo.encode(rdata));
4845 var data = rdata.data;
4847 if (this.uploadComplete) {
4848 Roo.MessageBox.hide();
4853 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
4854 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
4857 this.uploadProgress.defer(2000,this);
4860 failure: function(data) {
4861 Roo.log('progress url failed ');
4872 // run get Values on the form, so it syncs any secondary forms.
4873 this.form.getValues();
4875 var o = this.options;
4876 var method = this.getMethod();
4877 var isPost = method == 'POST';
4878 if(o.clientValidation === false || this.form.isValid()){
4880 if (this.form.progressUrl) {
4881 this.form.findField('UPLOAD_IDENTIFIER').setValue(
4882 (new Date() * 1) + '' + Math.random());
4887 Roo.Ajax.request(Roo.apply(this.createCallback(), {
4888 form:this.form.el.dom,
4889 url:this.getUrl(!isPost),
4891 params:isPost ? this.getParams() : null,
4892 isUpload: this.form.fileUpload
4895 this.uploadProgress();
4897 }else if (o.clientValidation !== false){ // client validation failed
4898 this.failureType = Roo.form.Action.CLIENT_INVALID;
4899 this.form.afterAction(this, false);
4903 success : function(response)
4905 this.uploadComplete= true;
4906 if (this.haveProgress) {
4907 Roo.MessageBox.hide();
4911 var result = this.processResponse(response);
4912 if(result === true || result.success){
4913 this.form.afterAction(this, true);
4917 this.form.markInvalid(result.errors);
4918 this.failureType = Roo.form.Action.SERVER_INVALID;
4920 this.form.afterAction(this, false);
4922 failure : function(response)
4924 this.uploadComplete= true;
4925 if (this.haveProgress) {
4926 Roo.MessageBox.hide();
4929 this.response = response;
4930 this.failureType = Roo.form.Action.CONNECT_FAILURE;
4931 this.form.afterAction(this, false);
4934 handleResponse : function(response){
4935 if(this.form.errorReader){
4936 var rs = this.form.errorReader.read(response);
4939 for(var i = 0, len = rs.records.length; i < len; i++) {
4940 var r = rs.records[i];
4944 if(errors.length < 1){
4948 success : rs.success,
4954 ret = Roo.decode(response.responseText);
4958 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
4968 Roo.form.Action.Load = function(form, options){
4969 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
4970 this.reader = this.form.reader;
4973 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
4978 Roo.Ajax.request(Roo.apply(
4979 this.createCallback(), {
4980 method:this.getMethod(),
4981 url:this.getUrl(false),
4982 params:this.getParams()
4986 success : function(response){
4988 var result = this.processResponse(response);
4989 if(result === true || !result.success || !result.data){
4990 this.failureType = Roo.form.Action.LOAD_FAILURE;
4991 this.form.afterAction(this, false);
4994 this.form.clearInvalid();
4995 this.form.setValues(result.data);
4996 this.form.afterAction(this, true);
4999 handleResponse : function(response){
5000 if(this.form.reader){
5001 var rs = this.form.reader.read(response);
5002 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
5004 success : rs.success,
5008 return Roo.decode(response.responseText);
5012 Roo.form.Action.ACTION_TYPES = {
5013 'load' : Roo.form.Action.Load,
5014 'submit' : Roo.form.Action.Submit
5023 * @class Roo.bootstrap.Form
5024 * @extends Roo.bootstrap.Component
5025 * Bootstrap Form class
5026 * @cfg {String} method GET | POST (default POST)
5027 * @cfg {String} labelAlign top | left (default top)
5028 * @cfg {String} align left | right - for navbars
5033 * @param {Object} config The config object
5037 Roo.bootstrap.Form = function(config){
5038 Roo.bootstrap.Form.superclass.constructor.call(this, config);
5041 * @event clientvalidation
5042 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
5043 * @param {Form} this
5044 * @param {Boolean} valid true if the form has passed client-side validation
5046 clientvalidation: true,
5048 * @event beforeaction
5049 * Fires before any action is performed. Return false to cancel the action.
5050 * @param {Form} this
5051 * @param {Action} action The action to be performed
5055 * @event actionfailed
5056 * Fires when an action fails.
5057 * @param {Form} this
5058 * @param {Action} action The action that failed
5060 actionfailed : true,
5062 * @event actioncomplete
5063 * Fires when an action is completed.
5064 * @param {Form} this
5065 * @param {Action} action The action that completed
5067 actioncomplete : true
5072 Roo.extend(Roo.bootstrap.Form, Roo.bootstrap.Component, {
5075 * @cfg {String} method
5076 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
5081 * The URL to use for form actions if one isn't supplied in the action options.
5084 * @cfg {Boolean} fileUpload
5085 * Set to true if this form is a file upload.
5089 * @cfg {Object} baseParams
5090 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
5094 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
5098 * @cfg {Sting} align (left|right) for navbar forms
5103 activeAction : null,
5106 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5107 * element by passing it or its id or mask the form itself by passing in true.
5110 waitMsgTarget : false,
5115 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
5116 * element by passing it or its id or mask the form itself by passing in true.
5120 getAutoCreate : function(){
5124 method : this.method || 'POST',
5125 id : this.id || Roo.id(),
5128 if (this.parent().xtype.match(/^Nav/)) {
5129 cfg.cls = 'navbar-form navbar-' + this.align;
5133 if (this.labelAlign == 'left' ) {
5134 cfg.cls += ' form-horizontal';
5140 initEvents : function()
5142 this.el.on('submit', this.onSubmit, this);
5147 onSubmit : function(e){
5152 * Returns true if client-side validation on the form is successful.
5155 isValid : function(){
5156 var items = this.getItems();
5158 items.each(function(f){
5167 * Returns true if any fields in this form have changed since their original load.
5170 isDirty : function(){
5172 var items = this.getItems();
5173 items.each(function(f){
5183 * Performs a predefined action (submit or load) or custom actions you define on this form.
5184 * @param {String} actionName The name of the action type
5185 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
5186 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
5187 * accept other config options):
5189 Property Type Description
5190 ---------------- --------------- ----------------------------------------------------------------------------------
5191 url String The url for the action (defaults to the form's url)
5192 method String The form method to use (defaults to the form's method, or POST if not defined)
5193 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
5194 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
5195 validate the form on the client (defaults to false)
5197 * @return {BasicForm} this
5199 doAction : function(action, options){
5200 if(typeof action == 'string'){
5201 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
5203 if(this.fireEvent('beforeaction', this, action) !== false){
5204 this.beforeAction(action);
5205 action.run.defer(100, action);
5211 beforeAction : function(action){
5212 var o = action.options;
5214 // not really supported yet.. ??
5216 //if(this.waitMsgTarget === true){
5217 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
5218 //}else if(this.waitMsgTarget){
5219 // this.waitMsgTarget = Roo.get(this.waitMsgTarget);
5220 // this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
5222 // Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
5228 afterAction : function(action, success){
5229 this.activeAction = null;
5230 var o = action.options;
5232 //if(this.waitMsgTarget === true){
5234 //}else if(this.waitMsgTarget){
5235 // this.waitMsgTarget.unmask();
5237 // Roo.MessageBox.updateProgress(1);
5238 // Roo.MessageBox.hide();
5245 Roo.callback(o.success, o.scope, [this, action]);
5246 this.fireEvent('actioncomplete', this, action);
5250 // failure condition..
5251 // we have a scenario where updates need confirming.
5252 // eg. if a locking scenario exists..
5253 // we look for { errors : { needs_confirm : true }} in the response.
5255 (typeof(action.result) != 'undefined') &&
5256 (typeof(action.result.errors) != 'undefined') &&
5257 (typeof(action.result.errors.needs_confirm) != 'undefined')
5260 Roo.log("not supported yet");
5263 Roo.MessageBox.confirm(
5264 "Change requires confirmation",
5265 action.result.errorMsg,
5270 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
5280 Roo.callback(o.failure, o.scope, [this, action]);
5281 // show an error message if no failed handler is set..
5282 if (!this.hasListener('actionfailed')) {
5283 Roo.log("need to add dialog support");
5285 Roo.MessageBox.alert("Error",
5286 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
5287 action.result.errorMsg :
5288 "Saving Failed, please check your entries or try again"
5293 this.fireEvent('actionfailed', this, action);
5298 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
5299 * @param {String} id The value to search for
5302 findField : function(id){
5303 var items = this.getItems();
5304 var field = items.get(id);
5306 items.each(function(f){
5307 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
5314 return field || null;
5317 * Mark fields in this form invalid in bulk.
5318 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
5319 * @return {BasicForm} this
5321 markInvalid : function(errors){
5322 if(errors instanceof Array){
5323 for(var i = 0, len = errors.length; i < len; i++){
5324 var fieldError = errors[i];
5325 var f = this.findField(fieldError.id);
5327 f.markInvalid(fieldError.msg);
5333 if(typeof errors[id] != 'function' && (field = this.findField(id))){
5334 field.markInvalid(errors[id]);
5338 //Roo.each(this.childForms || [], function (f) {
5339 // f.markInvalid(errors);
5346 * Set values for fields in this form in bulk.
5347 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
5348 * @return {BasicForm} this
5350 setValues : function(values){
5351 if(values instanceof Array){ // array of objects
5352 for(var i = 0, len = values.length; i < len; i++){
5354 var f = this.findField(v.id);
5356 f.setValue(v.value);
5357 if(this.trackResetOnLoad){
5358 f.originalValue = f.getValue();
5362 }else{ // object hash
5365 if(typeof values[id] != 'function' && (field = this.findField(id))){
5367 if (field.setFromData &&
5369 field.displayField &&
5370 // combos' with local stores can
5371 // be queried via setValue()
5372 // to set their value..
5373 (field.store && !field.store.isLocal)
5377 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
5378 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
5379 field.setFromData(sd);
5382 field.setValue(values[id]);
5386 if(this.trackResetOnLoad){
5387 field.originalValue = field.getValue();
5393 //Roo.each(this.childForms || [], function (f) {
5394 // f.setValues(values);
5401 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
5402 * they are returned as an array.
5403 * @param {Boolean} asString
5406 getValues : function(asString){
5407 //if (this.childForms) {
5408 // copy values from the child forms
5409 // Roo.each(this.childForms, function (f) {
5410 // this.setValues(f.getValues());
5416 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
5417 if(asString === true){
5420 return Roo.urlDecode(fs);
5424 * Returns the fields in this form as an object with key/value pairs.
5425 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
5428 getFieldValues : function(with_hidden)
5430 var items = this.getItems();
5432 items.each(function(f){
5436 var v = f.getValue();
5437 if (f.inputType =='radio') {
5438 if (typeof(ret[f.getName()]) == 'undefined') {
5439 ret[f.getName()] = ''; // empty..
5442 if (!f.el.dom.checked) {
5450 // not sure if this supported any more..
5451 if ((typeof(v) == 'object') && f.getRawValue) {
5452 v = f.getRawValue() ; // dates..
5454 // combo boxes where name != hiddenName...
5455 if (f.name != f.getName()) {
5456 ret[f.name] = f.getRawValue();
5458 ret[f.getName()] = v;
5465 * Clears all invalid messages in this form.
5466 * @return {BasicForm} this
5468 clearInvalid : function(){
5469 var items = this.getItems();
5471 items.each(function(f){
5482 * @return {BasicForm} this
5485 var items = this.getItems();
5486 items.each(function(f){
5490 Roo.each(this.childForms || [], function (f) {
5497 getItems : function()
5499 var r=new Roo.util.MixedCollection(false, function(o){
5500 return o.id || (o.id = Roo.id());
5502 var iter = function(el) {
5509 Roo.each(el.items,function(e) {
5528 * Ext JS Library 1.1.1
5529 * Copyright(c) 2006-2007, Ext JS, LLC.
5531 * Originally Released Under LGPL - original licence link has changed is not relivant.
5534 * <script type="text/javascript">
5537 * @class Roo.form.VTypes
5538 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
5541 Roo.form.VTypes = function(){
5542 // closure these in so they are only created once.
5543 var alpha = /^[a-zA-Z_]+$/;
5544 var alphanum = /^[a-zA-Z0-9_]+$/;
5545 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
5546 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
5548 // All these messages and functions are configurable
5551 * The function used to validate email addresses
5552 * @param {String} value The email address
5554 'email' : function(v){
5555 return email.test(v);
5558 * The error text to display when the email validation function returns false
5561 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
5563 * The keystroke filter mask to be applied on email input
5566 'emailMask' : /[a-z0-9_\.\-@]/i,
5569 * The function used to validate URLs
5570 * @param {String} value The URL
5572 'url' : function(v){
5576 * The error text to display when the url validation function returns false
5579 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
5582 * The function used to validate alpha values
5583 * @param {String} value The value
5585 'alpha' : function(v){
5586 return alpha.test(v);
5589 * The error text to display when the alpha validation function returns false
5592 'alphaText' : 'This field should only contain letters and _',
5594 * The keystroke filter mask to be applied on alpha input
5597 'alphaMask' : /[a-z_]/i,
5600 * The function used to validate alphanumeric values
5601 * @param {String} value The value
5603 'alphanum' : function(v){
5604 return alphanum.test(v);
5607 * The error text to display when the alphanumeric validation function returns false
5610 'alphanumText' : 'This field should only contain letters, numbers and _',
5612 * The keystroke filter mask to be applied on alphanumeric input
5615 'alphanumMask' : /[a-z0-9_]/i
5625 * @class Roo.bootstrap.Input
5626 * @extends Roo.bootstrap.Component
5627 * Bootstrap Input class
5628 * @cfg {Boolean} disabled is it disabled
5629 * @cfg {String} fieldLabel - the label associated
5630 * @cfg {String} inputType button | checkbox | email | file | hidden | image | number | password | radio | range | reset | search | submit | text
5631 * @cfg {String} name name of the input
5632 * @cfg {string} fieldLabel - the label associated
5633 * @cfg {string} inputType - input / file submit ...
5634 * @cfg {string} placeholder - placeholder to put in text.
5635 * @cfg {string} before - input group add on before
5636 * @cfg {string} after - input group add on after
5637 * @cfg {string} size - (lg|sm) or leave empty..
5638 * @cfg {Number} xs colspan out of 12 for mobile-sized screens
5639 * @cfg {Number} sm colspan out of 12 for tablet-sized screens
5640 * @cfg {Number} md colspan out of 12 for computer-sized screens
5641 * @cfg {Number} lg colspan out of 12 for large computer-sized screens
5642 * @cfg {string} value default value of the input
5643 * @cfg {Number} labelWidth set the width of label (0-12)
5644 * @cfg {String} labelAlign (top|left)
5645 * @cfg {Boolean} readOnly Specifies that the field should be read-only
5649 * Create a new Input
5650 * @param {Object} config The config object
5653 Roo.bootstrap.Input = function(config){
5654 Roo.bootstrap.Input.superclass.constructor.call(this, config);
5659 * Fires when this field receives input focus.
5660 * @param {Roo.form.Field} this
5665 * Fires when this field loses input focus.
5666 * @param {Roo.form.Field} this
5671 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
5672 * {@link Roo.EventObject#getKey} to determine which key was pressed.
5673 * @param {Roo.form.Field} this
5674 * @param {Roo.EventObject} e The event object
5679 * Fires just before the field blurs if the field value has changed.
5680 * @param {Roo.form.Field} this
5681 * @param {Mixed} newValue The new value
5682 * @param {Mixed} oldValue The original value
5687 * Fires after the field has been marked as invalid.
5688 * @param {Roo.form.Field} this
5689 * @param {String} msg The validation message
5694 * Fires after the field has been validated with no errors.
5695 * @param {Roo.form.Field} this
5700 * Fires after the key up
5701 * @param {Roo.form.Field} this
5702 * @param {Roo.EventObject} e The event Object
5708 Roo.extend(Roo.bootstrap.Input, Roo.bootstrap.Component, {
5710 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
5711 automatic validation (defaults to "keyup").
5713 validationEvent : "keyup",
5715 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
5717 validateOnBlur : true,
5719 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
5721 validationDelay : 250,
5723 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
5725 focusClass : "x-form-focus", // not needed???
5729 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
5731 invalidClass : "has-error",
5734 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
5736 selectOnFocus : false,
5739 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
5743 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
5748 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
5750 disableKeyFilter : false,
5753 * @cfg {Boolean} disabled True to disable the field (defaults to false).
5757 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
5761 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
5763 blankText : "This field is required",
5766 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
5770 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
5772 maxLength : Number.MAX_VALUE,
5774 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
5776 minLengthText : "The minimum length for this field is {0}",
5778 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
5780 maxLengthText : "The maximum length for this field is {0}",
5784 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
5785 * If available, this function will be called only after the basic validators all return true, and will be passed the
5786 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
5790 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
5791 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
5792 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
5796 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
5819 parentLabelAlign : function()
5822 while (parent.parent()) {
5823 parent = parent.parent();
5824 if (typeof(parent.labelAlign) !='undefined') {
5825 return parent.labelAlign;
5832 getAutoCreate : function(){
5834 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
5840 if(this.inputType != 'hidden'){
5841 cfg.cls = 'form-group' //input-group
5847 type : this.inputType,
5849 cls : 'form-control',
5850 placeholder : this.placeholder || ''
5854 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
5855 input.maxLength = this.maxLength;
5858 if (this.disabled) {
5859 input.disabled=true;
5862 if (this.readOnly) {
5863 input.readonly=true;
5867 input.name = this.name;
5870 input.cls += ' input-' + this.size;
5873 ['xs','sm','md','lg'].map(function(size){
5874 if (settings[size]) {
5875 cfg.cls += ' col-' + size + '-' + settings[size];
5879 var inputblock = input;
5881 if (this.before || this.after) {
5884 cls : 'input-group',
5888 inputblock.cn.push({
5890 cls : 'input-group-addon',
5894 inputblock.cn.push(input);
5896 inputblock.cn.push({
5898 cls : 'input-group-addon',
5905 if (align ==='left' && this.fieldLabel.length) {
5906 Roo.log("left and has label");
5912 cls : 'control-label col-sm-' + this.labelWidth,
5913 html : this.fieldLabel
5917 cls : "col-sm-" + (12 - this.labelWidth),
5924 } else if ( this.fieldLabel.length) {
5930 //cls : 'input-group-addon',
5931 html : this.fieldLabel
5941 Roo.log(" no label && no align");
5950 Roo.log('input-parentType: ' + this.parentType);
5952 if (this.parentType === 'Navbar' && this.parent().bar) {
5953 cfg.cls += ' navbar-form';
5961 * return the real input element.
5963 inputEl: function ()
5965 return this.el.select('input.form-control',true).first();
5967 setDisabled : function(v)
5969 var i = this.inputEl().dom;
5971 i.removeAttribute('disabled');
5975 i.setAttribute('disabled','true');
5977 initEvents : function()
5980 this.inputEl().on("keydown" , this.fireKey, this);
5981 this.inputEl().on("focus", this.onFocus, this);
5982 this.inputEl().on("blur", this.onBlur, this);
5984 this.inputEl().relayEvent('keyup', this);
5986 // reference to original value for reset
5987 this.originalValue = this.getValue();
5988 //Roo.form.TextField.superclass.initEvents.call(this);
5989 if(this.validationEvent == 'keyup'){
5990 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
5991 this.inputEl().on('keyup', this.filterValidation, this);
5993 else if(this.validationEvent !== false){
5994 this.inputEl().on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
5997 if(this.selectOnFocus){
5998 this.on("focus", this.preFocus, this);
6001 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
6002 this.inputEl().on("keypress", this.filterKeys, this);
6005 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
6006 this.el.on("click", this.autoSize, this);
6009 if(this.inputEl().is('input[type=password]') && Roo.isSafari){
6010 this.inputEl().on('keydown', this.SafariOnKeyDown, this);
6014 filterValidation : function(e){
6015 if(!e.isNavKeyPress()){
6016 this.validationTask.delay(this.validationDelay);
6020 * Validates the field value
6021 * @return {Boolean} True if the value is valid, else false
6023 validate : function(){
6024 //if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
6025 if(this.disabled || this.validateValue(this.getRawValue())){
6026 this.clearInvalid();
6034 * Validates a value according to the field's validation rules and marks the field as invalid
6035 * if the validation fails
6036 * @param {Mixed} value The value to validate
6037 * @return {Boolean} True if the value is valid, else false
6039 validateValue : function(value){
6040 if(value.length < 1) { // if it's blank
6041 if(this.allowBlank){
6042 this.clearInvalid();
6045 this.markInvalid(this.blankText);
6049 if(value.length < this.minLength){
6050 this.markInvalid(String.format(this.minLengthText, this.minLength));
6053 if(value.length > this.maxLength){
6054 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
6058 var vt = Roo.form.VTypes;
6059 if(!vt[this.vtype](value, this)){
6060 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
6064 if(typeof this.validator == "function"){
6065 var msg = this.validator(value);
6067 this.markInvalid(msg);
6071 if(this.regex && !this.regex.test(value)){
6072 this.markInvalid(this.regexText);
6081 fireKey : function(e){
6082 //Roo.log('field ' + e.getKey());
6083 if(e.isNavKeyPress()){
6084 this.fireEvent("specialkey", this, e);
6087 focus : function (selectText){
6089 this.inputEl().focus();
6090 if(selectText === true){
6091 this.inputEl().dom.select();
6097 onFocus : function(){
6098 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6099 // this.el.addClass(this.focusClass);
6102 this.hasFocus = true;
6103 this.startValue = this.getValue();
6104 this.fireEvent("focus", this);
6108 beforeBlur : Roo.emptyFn,
6112 onBlur : function(){
6114 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
6115 //this.el.removeClass(this.focusClass);
6117 this.hasFocus = false;
6118 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
6121 var v = this.getValue();
6122 if(String(v) !== String(this.startValue)){
6123 this.fireEvent('change', this, v, this.startValue);
6125 this.fireEvent("blur", this);
6129 * Resets the current field value to the originally loaded value and clears any validation messages
6132 this.setValue(this.originalValue);
6133 this.clearInvalid();
6136 * Returns the name of the field
6137 * @return {Mixed} name The name field
6139 getName: function(){
6143 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
6144 * @return {Mixed} value The field value
6146 getValue : function(){
6147 return this.inputEl().getValue();
6150 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
6151 * @return {Mixed} value The field value
6153 getRawValue : function(){
6154 var v = this.inputEl().getValue();
6160 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
6161 * @param {Mixed} value The value to set
6163 setRawValue : function(v){
6164 return this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6167 selectText : function(start, end){
6168 var v = this.getRawValue();
6170 start = start === undefined ? 0 : start;
6171 end = end === undefined ? v.length : end;
6172 var d = this.inputEl().dom;
6173 if(d.setSelectionRange){
6174 d.setSelectionRange(start, end);
6175 }else if(d.createTextRange){
6176 var range = d.createTextRange();
6177 range.moveStart("character", start);
6178 range.moveEnd("character", v.length-end);
6185 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
6186 * @param {Mixed} value The value to set
6188 setValue : function(v){
6191 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
6197 processValue : function(value){
6198 if(this.stripCharsRe){
6199 var newValue = value.replace(this.stripCharsRe, '');
6200 if(newValue !== value){
6201 this.setRawValue(newValue);
6208 preFocus : function(){
6210 if(this.selectOnFocus){
6211 this.inputEl().dom.select();
6214 filterKeys : function(e){
6216 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
6219 var c = e.getCharCode(), cc = String.fromCharCode(c);
6220 if(Roo.isIE && (e.isSpecialKey() || !cc)){
6223 if(!this.maskRe.test(cc)){
6228 * Clear any invalid styles/messages for this field
6230 clearInvalid : function(){
6232 if(!this.el || this.preventMark){ // not rendered
6235 this.el.removeClass(this.invalidClass);
6237 switch(this.msgTarget){
6239 this.el.dom.qtip = '';
6242 this.el.dom.title = '';
6246 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
6251 this.errorIcon.dom.qtip = '';
6252 this.errorIcon.hide();
6253 this.un('resize', this.alignErrorIcon, this);
6257 var t = Roo.getDom(this.msgTarget);
6259 t.style.display = 'none';
6263 this.fireEvent('valid', this);
6266 * Mark this field as invalid
6267 * @param {String} msg The validation message
6269 markInvalid : function(msg){
6270 if(!this.el || this.preventMark){ // not rendered
6273 this.el.addClass(this.invalidClass);
6275 msg = msg || this.invalidText;
6276 switch(this.msgTarget){
6278 this.el.dom.qtip = msg;
6279 this.el.dom.qclass = 'x-form-invalid-tip';
6280 if(Roo.QuickTips){ // fix for floating editors interacting with DND
6281 Roo.QuickTips.enable();
6285 this.el.dom.title = msg;
6289 var elp = this.el.findParent('.x-form-element', 5, true);
6290 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
6291 this.errorEl.setWidth(elp.getWidth(true)-20);
6293 this.errorEl.update(msg);
6294 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
6297 if(!this.errorIcon){
6298 var elp = this.el.findParent('.x-form-element', 5, true);
6299 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
6301 this.alignErrorIcon();
6302 this.errorIcon.dom.qtip = msg;
6303 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
6304 this.errorIcon.show();
6305 this.on('resize', this.alignErrorIcon, this);
6308 var t = Roo.getDom(this.msgTarget);
6310 t.style.display = this.msgDisplay;
6314 this.fireEvent('invalid', this, msg);
6317 SafariOnKeyDown : function(event)
6319 // this is a workaround for a password hang bug on chrome/ webkit.
6321 var isSelectAll = false;
6323 if(this.inputEl().dom.selectionEnd > 0){
6324 isSelectAll = (this.inputEl().dom.selectionEnd - this.inputEl().dom.selectionStart - this.getValue().length == 0) ? true : false;
6326 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
6327 event.preventDefault();
6332 if(isSelectAll){ // backspace and delete key
6334 event.preventDefault();
6335 // this is very hacky as keydown always get's upper case.
6337 var cc = String.fromCharCode(event.getCharCode());
6338 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
6342 adjustWidth : function(tag, w){
6343 tag = tag.toLowerCase();
6344 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
6345 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
6349 if(tag == 'textarea'){
6352 }else if(Roo.isOpera){
6356 if(tag == 'textarea'){
6375 * @class Roo.bootstrap.TextArea
6376 * @extends Roo.bootstrap.Input
6377 * Bootstrap TextArea class
6378 * @cfg {Number} cols Specifies the visible width of a text area
6379 * @cfg {Number} rows Specifies the visible number of lines in a text area
6380 * @cfg {string} wrap (soft|hard)Specifies how the text in a text area is to be wrapped when submitted in a form
6381 * @cfg {string} resize (none|both|horizontal|vertical|inherit|initial)
6382 * @cfg {string} html text
6385 * Create a new TextArea
6386 * @param {Object} config The config object
6389 Roo.bootstrap.TextArea = function(config){
6390 Roo.bootstrap.TextArea.superclass.constructor.call(this, config);
6394 Roo.extend(Roo.bootstrap.TextArea, Roo.bootstrap.Input, {
6404 getAutoCreate : function(){
6406 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
6417 value : this.value || '',
6418 html: this.html || '',
6419 cls : 'form-control',
6420 placeholder : this.placeholder || ''
6424 if(this.maxLength && this.maxLength != Number.MAX_VALUE){
6425 input.maxLength = this.maxLength;
6429 input.style = (typeof(input.style) == 'undefined') ? 'resize:' + this.resize : input.style + 'resize:' + this.resize;
6433 input.cols = this.cols;
6436 if (this.readOnly) {
6437 input.readonly = true;
6441 input.name = this.name;
6445 input.cls = (typeof(input.cls) == 'undefined') ? 'input-' + this.size : input.cls + ' input-' + this.size;
6449 ['xs','sm','md','lg'].map(function(size){
6450 if (settings[size]) {
6451 cfg.cls += ' col-' + size + '-' + settings[size];
6455 var inputblock = input;
6457 if (this.before || this.after) {
6460 cls : 'input-group',
6464 inputblock.cn.push({
6466 cls : 'input-group-addon',
6470 inputblock.cn.push(input);
6472 inputblock.cn.push({
6474 cls : 'input-group-addon',
6481 if (align ==='left' && this.fieldLabel.length) {
6482 Roo.log("left and has label");
6488 cls : 'control-label col-sm-' + this.labelWidth,
6489 html : this.fieldLabel
6493 cls : "col-sm-" + (12 - this.labelWidth),
6500 } else if ( this.fieldLabel.length) {
6506 //cls : 'input-group-addon',
6507 html : this.fieldLabel
6517 Roo.log(" no label && no align");
6527 if (this.disabled) {
6528 input.disabled=true;
6535 * return the real textarea element.
6537 inputEl: function ()
6539 return this.el.select('textarea.form-control',true).first();
6547 * trigger field - base class for combo..
6552 * @class Roo.bootstrap.TriggerField
6553 * @extends Roo.bootstrap.Input
6554 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
6555 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
6556 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
6557 * for which you can provide a custom implementation. For example:
6559 var trigger = new Roo.bootstrap.TriggerField();
6560 trigger.onTriggerClick = myTriggerFn;
6561 trigger.applyTo('my-field');
6564 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
6565 * {@link Roo.bootstrap.DateField} and {@link Roo.bootstrap.ComboBox} are perfect examples of this.
6566 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
6567 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
6569 * Create a new TriggerField.
6570 * @param {Object} config Configuration options (valid {@Roo.bootstrap.Input} config options will also be applied
6571 * to the base TextField)
6573 Roo.bootstrap.TriggerField = function(config){
6574 this.mimicing = false;
6575 Roo.bootstrap.TriggerField.superclass.constructor.call(this, config);
6578 Roo.extend(Roo.bootstrap.TriggerField, Roo.bootstrap.Input, {
6580 * @cfg {String} triggerClass A CSS class to apply to the trigger
6583 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
6587 /** @cfg {Boolean} grow @hide */
6588 /** @cfg {Number} growMin @hide */
6589 /** @cfg {Number} growMax @hide */
6595 autoSize: Roo.emptyFn,
6602 actionMode : 'wrap',
6606 getAutoCreate : function(){
6608 var parent = this.parent();
6610 var align = this.parentLabelAlign();
6615 cls: 'form-group' //input-group
6622 type : this.inputType,
6623 cls : 'form-control',
6624 autocomplete: 'off',
6625 placeholder : this.placeholder || ''
6629 input.name = this.name;
6632 input.cls += ' input-' + this.size;
6635 if (this.disabled) {
6636 input.disabled=true;
6639 var inputblock = input;
6641 if (this.before || this.after) {
6644 cls : 'input-group',
6648 inputblock.cn.push({
6650 cls : 'input-group-addon',
6654 inputblock.cn.push(input);
6656 inputblock.cn.push({
6658 cls : 'input-group-addon',
6671 cls: 'form-hidden-field'
6679 Roo.log('multiple');
6687 cls: 'form-hidden-field'
6691 cls: 'select2-choices',
6695 cls: 'select2-search-field',
6708 cls: 'select2-container input-group',
6713 cls: 'typeahead typeahead-long dropdown-menu',
6714 style: 'display:none'
6722 cls : 'input-group-addon btn dropdown-toggle',
6730 cls: 'combobox-clear',
6744 combobox.cls += ' select2-container-multi';
6747 if (align ==='left' && this.fieldLabel.length) {
6749 Roo.log("left and has label");
6755 cls : 'control-label col-sm-' + this.labelWidth,
6756 html : this.fieldLabel
6760 cls : "col-sm-" + (12 - this.labelWidth),
6767 } else if ( this.fieldLabel.length) {
6773 //cls : 'input-group-addon',
6774 html : this.fieldLabel
6784 Roo.log(" no label && no align");
6791 ['xs','sm','md','lg'].map(function(size){
6792 if (settings[size]) {
6793 cfg.cls += ' col-' + size + '-' + settings[size];
6804 onResize : function(w, h){
6805 // Roo.bootstrap.TriggerField.superclass.onResize.apply(this, arguments);
6806 // if(typeof w == 'number'){
6807 // var x = w - this.trigger.getWidth();
6808 // this.inputEl().setWidth(this.adjustWidth('input', x));
6809 // this.trigger.setStyle('left', x+'px');
6814 adjustSize : Roo.BoxComponent.prototype.adjustSize,
6817 getResizeEl : function(){
6818 return this.inputEl();
6822 getPositionEl : function(){
6823 return this.inputEl();
6827 alignErrorIcon : function(){
6828 this.errorIcon.alignTo(this.inputEl(), 'tl-tr', [2, 0]);
6832 initEvents : function(){
6834 Roo.bootstrap.TriggerField.superclass.initEvents.call(this);
6835 //this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
6837 this.trigger = this.el.select('span.dropdown-toggle',true).first();
6838 if(this.hideTrigger){
6839 this.trigger.setDisplayed(false);
6841 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
6845 this.inputEl().on("click", this.onTriggerClick, this, {preventDefault:true});
6848 //this.trigger.addClassOnOver('x-form-trigger-over');
6849 //this.trigger.addClassOnClick('x-form-trigger-click');
6852 // this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
6857 initTrigger : function(){
6862 onDestroy : function(){
6864 this.trigger.removeAllListeners();
6865 // this.trigger.remove();
6868 // this.wrap.remove();
6870 Roo.bootstrap.TriggerField.superclass.onDestroy.call(this);
6874 onFocus : function(){
6875 Roo.bootstrap.TriggerField.superclass.onFocus.call(this);
6878 this.wrap.addClass('x-trigger-wrap-focus');
6879 this.mimicing = true;
6880 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
6881 if(this.monitorTab){
6882 this.el.on("keydown", this.checkTab, this);
6889 checkTab : function(e){
6890 if(e.getKey() == e.TAB){
6896 onBlur : function(){
6901 mimicBlur : function(e, t){
6903 if(!this.wrap.contains(t) && this.validateBlur()){
6910 triggerBlur : function(){
6911 this.mimicing = false;
6912 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
6913 if(this.monitorTab){
6914 this.el.un("keydown", this.checkTab, this);
6916 //this.wrap.removeClass('x-trigger-wrap-focus');
6917 Roo.bootstrap.TriggerField.superclass.onBlur.call(this);
6921 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
6922 validateBlur : function(e, t){
6927 onDisable : function(){
6928 Roo.bootstrap.TriggerField.superclass.onDisable.call(this);
6930 // this.wrap.addClass('x-item-disabled');
6935 onEnable : function(){
6936 Roo.bootstrap.TriggerField.superclass.onEnable.call(this);
6938 // this.el.removeClass('x-item-disabled');
6943 onShow : function(){
6944 var ae = this.getActionEl();
6947 ae.dom.style.display = '';
6948 ae.dom.style.visibility = 'visible';
6954 onHide : function(){
6955 var ae = this.getActionEl();
6956 ae.dom.style.display = 'none';
6960 * The function that should handle the trigger's click event. This method does nothing by default until overridden
6961 * by an implementing function.
6963 * @param {EventObject} e
6965 onTriggerClick : Roo.emptyFn
6969 * Ext JS Library 1.1.1
6970 * Copyright(c) 2006-2007, Ext JS, LLC.
6972 * Originally Released Under LGPL - original licence link has changed is not relivant.
6975 * <script type="text/javascript">
6980 * @class Roo.data.SortTypes
6982 * Defines the default sorting (casting?) comparison functions used when sorting data.
6984 Roo.data.SortTypes = {
6986 * Default sort that does nothing
6987 * @param {Mixed} s The value being converted
6988 * @return {Mixed} The comparison value
6995 * The regular expression used to strip tags
6999 stripTagsRE : /<\/?[^>]+>/gi,
7002 * Strips all HTML tags to sort on text only
7003 * @param {Mixed} s The value being converted
7004 * @return {String} The comparison value
7006 asText : function(s){
7007 return String(s).replace(this.stripTagsRE, "");
7011 * Strips all HTML tags to sort on text only - Case insensitive
7012 * @param {Mixed} s The value being converted
7013 * @return {String} The comparison value
7015 asUCText : function(s){
7016 return String(s).toUpperCase().replace(this.stripTagsRE, "");
7020 * Case insensitive string
7021 * @param {Mixed} s The value being converted
7022 * @return {String} The comparison value
7024 asUCString : function(s) {
7025 return String(s).toUpperCase();
7030 * @param {Mixed} s The value being converted
7031 * @return {Number} The comparison value
7033 asDate : function(s) {
7037 if(s instanceof Date){
7040 return Date.parse(String(s));
7045 * @param {Mixed} s The value being converted
7046 * @return {Float} The comparison value
7048 asFloat : function(s) {
7049 var val = parseFloat(String(s).replace(/,/g, ""));
7050 if(isNaN(val)) val = 0;
7056 * @param {Mixed} s The value being converted
7057 * @return {Number} The comparison value
7059 asInt : function(s) {
7060 var val = parseInt(String(s).replace(/,/g, ""));
7061 if(isNaN(val)) val = 0;
7066 * Ext JS Library 1.1.1
7067 * Copyright(c) 2006-2007, Ext JS, LLC.
7069 * Originally Released Under LGPL - original licence link has changed is not relivant.
7072 * <script type="text/javascript">
7076 * @class Roo.data.Record
7077 * Instances of this class encapsulate both record <em>definition</em> information, and record
7078 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
7079 * to access Records cached in an {@link Roo.data.Store} object.<br>
7081 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
7082 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
7085 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
7087 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
7088 * {@link #create}. The parameters are the same.
7089 * @param {Array} data An associative Array of data values keyed by the field name.
7090 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
7091 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
7092 * not specified an integer id is generated.
7094 Roo.data.Record = function(data, id){
7095 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
7100 * Generate a constructor for a specific record layout.
7101 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
7102 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
7103 * Each field definition object may contain the following properties: <ul>
7104 * <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,
7105 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
7106 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
7107 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
7108 * is being used, then this is a string containing the javascript expression to reference the data relative to
7109 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
7110 * to the data item relative to the record element. If the mapping expression is the same as the field name,
7111 * this may be omitted.</p></li>
7112 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
7113 * <ul><li>auto (Default, implies no conversion)</li>
7118 * <li>date</li></ul></p></li>
7119 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
7120 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
7121 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
7122 * by the Reader into an object that will be stored in the Record. It is passed the
7123 * following parameters:<ul>
7124 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
7126 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
7128 * <br>usage:<br><pre><code>
7129 var TopicRecord = Roo.data.Record.create(
7130 {name: 'title', mapping: 'topic_title'},
7131 {name: 'author', mapping: 'username'},
7132 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
7133 {name: 'lastPost', mapping: 'post_time', type: 'date'},
7134 {name: 'lastPoster', mapping: 'user2'},
7135 {name: 'excerpt', mapping: 'post_text'}
7138 var myNewRecord = new TopicRecord({
7139 title: 'Do my job please',
7142 lastPost: new Date(),
7143 lastPoster: 'Animal',
7144 excerpt: 'No way dude!'
7146 myStore.add(myNewRecord);
7151 Roo.data.Record.create = function(o){
7153 f.superclass.constructor.apply(this, arguments);
7155 Roo.extend(f, Roo.data.Record);
7156 var p = f.prototype;
7157 p.fields = new Roo.util.MixedCollection(false, function(field){
7160 for(var i = 0, len = o.length; i < len; i++){
7161 p.fields.add(new Roo.data.Field(o[i]));
7163 f.getField = function(name){
7164 return p.fields.get(name);
7169 Roo.data.Record.AUTO_ID = 1000;
7170 Roo.data.Record.EDIT = 'edit';
7171 Roo.data.Record.REJECT = 'reject';
7172 Roo.data.Record.COMMIT = 'commit';
7174 Roo.data.Record.prototype = {
7176 * Readonly flag - true if this record has been modified.
7185 join : function(store){
7190 * Set the named field to the specified value.
7191 * @param {String} name The name of the field to set.
7192 * @param {Object} value The value to set the field to.
7194 set : function(name, value){
7195 if(this.data[name] == value){
7202 if(typeof this.modified[name] == 'undefined'){
7203 this.modified[name] = this.data[name];
7205 this.data[name] = value;
7206 if(!this.editing && this.store){
7207 this.store.afterEdit(this);
7212 * Get the value of the named field.
7213 * @param {String} name The name of the field to get the value of.
7214 * @return {Object} The value of the field.
7216 get : function(name){
7217 return this.data[name];
7221 beginEdit : function(){
7222 this.editing = true;
7227 cancelEdit : function(){
7228 this.editing = false;
7229 delete this.modified;
7233 endEdit : function(){
7234 this.editing = false;
7235 if(this.dirty && this.store){
7236 this.store.afterEdit(this);
7241 * Usually called by the {@link Roo.data.Store} which owns the Record.
7242 * Rejects all changes made to the Record since either creation, or the last commit operation.
7243 * Modified fields are reverted to their original values.
7245 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7246 * of reject operations.
7248 reject : function(){
7249 var m = this.modified;
7251 if(typeof m[n] != "function"){
7252 this.data[n] = m[n];
7256 delete this.modified;
7257 this.editing = false;
7259 this.store.afterReject(this);
7264 * Usually called by the {@link Roo.data.Store} which owns the Record.
7265 * Commits all changes made to the Record since either creation, or the last commit operation.
7267 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
7268 * of commit operations.
7270 commit : function(){
7272 delete this.modified;
7273 this.editing = false;
7275 this.store.afterCommit(this);
7280 hasError : function(){
7281 return this.error != null;
7285 clearError : function(){
7290 * Creates a copy of this record.
7291 * @param {String} id (optional) A new record id if you don't want to use this record's id
7294 copy : function(newId) {
7295 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
7299 * Ext JS Library 1.1.1
7300 * Copyright(c) 2006-2007, Ext JS, LLC.
7302 * Originally Released Under LGPL - original licence link has changed is not relivant.
7305 * <script type="text/javascript">
7311 * @class Roo.data.Store
7312 * @extends Roo.util.Observable
7313 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
7314 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
7316 * 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
7317 * has no knowledge of the format of the data returned by the Proxy.<br>
7319 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
7320 * instances from the data object. These records are cached and made available through accessor functions.
7322 * Creates a new Store.
7323 * @param {Object} config A config object containing the objects needed for the Store to access data,
7324 * and read the data into Records.
7326 Roo.data.Store = function(config){
7327 this.data = new Roo.util.MixedCollection(false);
7328 this.data.getKey = function(o){
7331 this.baseParams = {};
7338 "multisort" : "_multisort"
7341 if(config && config.data){
7342 this.inlineData = config.data;
7346 Roo.apply(this, config);
7348 if(this.reader){ // reader passed
7349 this.reader = Roo.factory(this.reader, Roo.data);
7350 this.reader.xmodule = this.xmodule || false;
7351 if(!this.recordType){
7352 this.recordType = this.reader.recordType;
7354 if(this.reader.onMetaChange){
7355 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
7359 if(this.recordType){
7360 this.fields = this.recordType.prototype.fields;
7366 * @event datachanged
7367 * Fires when the data cache has changed, and a widget which is using this Store
7368 * as a Record cache should refresh its view.
7369 * @param {Store} this
7374 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
7375 * @param {Store} this
7376 * @param {Object} meta The JSON metadata
7381 * Fires when Records have been added to the Store
7382 * @param {Store} this
7383 * @param {Roo.data.Record[]} records The array of Records added
7384 * @param {Number} index The index at which the record(s) were added
7389 * Fires when a Record has been removed from the Store
7390 * @param {Store} this
7391 * @param {Roo.data.Record} record The Record that was removed
7392 * @param {Number} index The index at which the record was removed
7397 * Fires when a Record has been updated
7398 * @param {Store} this
7399 * @param {Roo.data.Record} record The Record that was updated
7400 * @param {String} operation The update operation being performed. Value may be one of:
7402 Roo.data.Record.EDIT
7403 Roo.data.Record.REJECT
7404 Roo.data.Record.COMMIT
7410 * Fires when the data cache has been cleared.
7411 * @param {Store} this
7416 * Fires before a request is made for a new data object. If the beforeload handler returns false
7417 * the load action will be canceled.
7418 * @param {Store} this
7419 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7423 * @event beforeloadadd
7424 * Fires after a new set of Records has been loaded.
7425 * @param {Store} this
7426 * @param {Roo.data.Record[]} records The Records that were loaded
7427 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7429 beforeloadadd : true,
7432 * Fires after a new set of Records has been loaded, before they are added to the store.
7433 * @param {Store} this
7434 * @param {Roo.data.Record[]} records The Records that were loaded
7435 * @param {Object} options The loading options that were specified (see {@link #load} for details)
7436 * @params {Object} return from reader
7440 * @event loadexception
7441 * Fires if an exception occurs in the Proxy during loading.
7442 * Called with the signature of the Proxy's "loadexception" event.
7443 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
7446 * @param {Object} return from JsonData.reader() - success, totalRecords, records
7447 * @param {Object} load options
7448 * @param {Object} jsonData from your request (normally this contains the Exception)
7450 loadexception : true
7454 this.proxy = Roo.factory(this.proxy, Roo.data);
7455 this.proxy.xmodule = this.xmodule || false;
7456 this.relayEvents(this.proxy, ["loadexception"]);
7458 this.sortToggle = {};
7459 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
7461 Roo.data.Store.superclass.constructor.call(this);
7463 if(this.inlineData){
7464 this.loadData(this.inlineData);
7465 delete this.inlineData;
7469 Roo.extend(Roo.data.Store, Roo.util.Observable, {
7471 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
7472 * without a remote query - used by combo/forms at present.
7476 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
7479 * @cfg {Array} data Inline data to be loaded when the store is initialized.
7482 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
7483 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
7486 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
7487 * on any HTTP request
7490 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
7493 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
7497 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
7498 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
7503 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
7504 * loaded or when a record is removed. (defaults to false).
7506 pruneModifiedRecords : false,
7512 * Add Records to the Store and fires the add event.
7513 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7515 add : function(records){
7516 records = [].concat(records);
7517 for(var i = 0, len = records.length; i < len; i++){
7518 records[i].join(this);
7520 var index = this.data.length;
7521 this.data.addAll(records);
7522 this.fireEvent("add", this, records, index);
7526 * Remove a Record from the Store and fires the remove event.
7527 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
7529 remove : function(record){
7530 var index = this.data.indexOf(record);
7531 this.data.removeAt(index);
7532 if(this.pruneModifiedRecords){
7533 this.modified.remove(record);
7535 this.fireEvent("remove", this, record, index);
7539 * Remove all Records from the Store and fires the clear event.
7541 removeAll : function(){
7543 if(this.pruneModifiedRecords){
7546 this.fireEvent("clear", this);
7550 * Inserts Records to the Store at the given index and fires the add event.
7551 * @param {Number} index The start index at which to insert the passed Records.
7552 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
7554 insert : function(index, records){
7555 records = [].concat(records);
7556 for(var i = 0, len = records.length; i < len; i++){
7557 this.data.insert(index, records[i]);
7558 records[i].join(this);
7560 this.fireEvent("add", this, records, index);
7564 * Get the index within the cache of the passed Record.
7565 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
7566 * @return {Number} The index of the passed Record. Returns -1 if not found.
7568 indexOf : function(record){
7569 return this.data.indexOf(record);
7573 * Get the index within the cache of the Record with the passed id.
7574 * @param {String} id The id of the Record to find.
7575 * @return {Number} The index of the Record. Returns -1 if not found.
7577 indexOfId : function(id){
7578 return this.data.indexOfKey(id);
7582 * Get the Record with the specified id.
7583 * @param {String} id The id of the Record to find.
7584 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
7586 getById : function(id){
7587 return this.data.key(id);
7591 * Get the Record at the specified index.
7592 * @param {Number} index The index of the Record to find.
7593 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
7595 getAt : function(index){
7596 return this.data.itemAt(index);
7600 * Returns a range of Records between specified indices.
7601 * @param {Number} startIndex (optional) The starting index (defaults to 0)
7602 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
7603 * @return {Roo.data.Record[]} An array of Records
7605 getRange : function(start, end){
7606 return this.data.getRange(start, end);
7610 storeOptions : function(o){
7611 o = Roo.apply({}, o);
7614 this.lastOptions = o;
7618 * Loads the Record cache from the configured Proxy using the configured Reader.
7620 * If using remote paging, then the first load call must specify the <em>start</em>
7621 * and <em>limit</em> properties in the options.params property to establish the initial
7622 * position within the dataset, and the number of Records to cache on each read from the Proxy.
7624 * <strong>It is important to note that for remote data sources, loading is asynchronous,
7625 * and this call will return before the new data has been loaded. Perform any post-processing
7626 * in a callback function, or in a "load" event handler.</strong>
7628 * @param {Object} options An object containing properties which control loading options:<ul>
7629 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
7630 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
7631 * passed the following arguments:<ul>
7632 * <li>r : Roo.data.Record[]</li>
7633 * <li>options: Options object from the load call</li>
7634 * <li>success: Boolean success indicator</li></ul></li>
7635 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
7636 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
7639 load : function(options){
7640 options = options || {};
7641 if(this.fireEvent("beforeload", this, options) !== false){
7642 this.storeOptions(options);
7643 var p = Roo.apply(options.params || {}, this.baseParams);
7644 // if meta was not loaded from remote source.. try requesting it.
7645 if (!this.reader.metaFromRemote) {
7648 if(this.sortInfo && this.remoteSort){
7649 var pn = this.paramNames;
7650 p[pn["sort"]] = this.sortInfo.field;
7651 p[pn["dir"]] = this.sortInfo.direction;
7653 if (this.multiSort) {
7654 var pn = this.paramNames;
7655 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
7658 this.proxy.load(p, this.reader, this.loadRecords, this, options);
7663 * Reloads the Record cache from the configured Proxy using the configured Reader and
7664 * the options from the last load operation performed.
7665 * @param {Object} options (optional) An object containing properties which may override the options
7666 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
7667 * the most recently used options are reused).
7669 reload : function(options){
7670 this.load(Roo.applyIf(options||{}, this.lastOptions));
7674 // Called as a callback by the Reader during a load operation.
7675 loadRecords : function(o, options, success){
7676 if(!o || success === false){
7677 if(success !== false){
7678 this.fireEvent("load", this, [], options, o);
7680 if(options.callback){
7681 options.callback.call(options.scope || this, [], options, false);
7685 // if data returned failure - throw an exception.
7686 if (o.success === false) {
7687 // show a message if no listener is registered.
7688 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
7689 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
7691 // loadmask wil be hooked into this..
7692 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
7695 var r = o.records, t = o.totalRecords || r.length;
7697 this.fireEvent("beforeloadadd", this, r, options, o);
7699 if(!options || options.add !== true){
7700 if(this.pruneModifiedRecords){
7703 for(var i = 0, len = r.length; i < len; i++){
7707 this.data = this.snapshot;
7708 delete this.snapshot;
7711 this.data.addAll(r);
7712 this.totalLength = t;
7714 this.fireEvent("datachanged", this);
7716 this.totalLength = Math.max(t, this.data.length+r.length);
7719 this.fireEvent("load", this, r, options, o);
7720 if(options.callback){
7721 options.callback.call(options.scope || this, r, options, true);
7727 * Loads data from a passed data block. A Reader which understands the format of the data
7728 * must have been configured in the constructor.
7729 * @param {Object} data The data block from which to read the Records. The format of the data expected
7730 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
7731 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
7733 loadData : function(o, append){
7734 var r = this.reader.readRecords(o);
7735 this.loadRecords(r, {add: append}, true);
7739 * Gets the number of cached records.
7741 * <em>If using paging, this may not be the total size of the dataset. If the data object
7742 * used by the Reader contains the dataset size, then the getTotalCount() function returns
7743 * the data set size</em>
7745 getCount : function(){
7746 return this.data.length || 0;
7750 * Gets the total number of records in the dataset as returned by the server.
7752 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
7753 * the dataset size</em>
7755 getTotalCount : function(){
7756 return this.totalLength || 0;
7760 * Returns the sort state of the Store as an object with two properties:
7762 field {String} The name of the field by which the Records are sorted
7763 direction {String} The sort order, "ASC" or "DESC"
7766 getSortState : function(){
7767 return this.sortInfo;
7771 applySort : function(){
7772 if(this.sortInfo && !this.remoteSort){
7773 var s = this.sortInfo, f = s.field;
7774 var st = this.fields.get(f).sortType;
7775 var fn = function(r1, r2){
7776 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
7777 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
7779 this.data.sort(s.direction, fn);
7780 if(this.snapshot && this.snapshot != this.data){
7781 this.snapshot.sort(s.direction, fn);
7787 * Sets the default sort column and order to be used by the next load operation.
7788 * @param {String} fieldName The name of the field to sort by.
7789 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7791 setDefaultSort : function(field, dir){
7792 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
7797 * If remote sorting is used, the sort is performed on the server, and the cache is
7798 * reloaded. If local sorting is used, the cache is sorted internally.
7799 * @param {String} fieldName The name of the field to sort by.
7800 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
7802 sort : function(fieldName, dir){
7803 var f = this.fields.get(fieldName);
7805 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
7807 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
7808 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
7813 this.sortToggle[f.name] = dir;
7814 this.sortInfo = {field: f.name, direction: dir};
7815 if(!this.remoteSort){
7817 this.fireEvent("datachanged", this);
7819 this.load(this.lastOptions);
7824 * Calls the specified function for each of the Records in the cache.
7825 * @param {Function} fn The function to call. The Record is passed as the first parameter.
7826 * Returning <em>false</em> aborts and exits the iteration.
7827 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
7829 each : function(fn, scope){
7830 this.data.each(fn, scope);
7834 * Gets all records modified since the last commit. Modified records are persisted across load operations
7835 * (e.g., during paging).
7836 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
7838 getModifiedRecords : function(){
7839 return this.modified;
7843 createFilterFn : function(property, value, anyMatch){
7844 if(!value.exec){ // not a regex
7845 value = String(value);
7846 if(value.length == 0){
7849 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
7852 return value.test(r.data[property]);
7857 * Sums the value of <i>property</i> for each record between start and end and returns the result.
7858 * @param {String} property A field on your records
7859 * @param {Number} start The record index to start at (defaults to 0)
7860 * @param {Number} end The last record index to include (defaults to length - 1)
7861 * @return {Number} The sum
7863 sum : function(property, start, end){
7864 var rs = this.data.items, v = 0;
7866 end = (end || end === 0) ? end : rs.length-1;
7868 for(var i = start; i <= end; i++){
7869 v += (rs[i].data[property] || 0);
7875 * Filter the records by a specified property.
7876 * @param {String} field A field on your records
7877 * @param {String/RegExp} value Either a string that the field
7878 * should start with or a RegExp to test against the field
7879 * @param {Boolean} anyMatch True to match any part not just the beginning
7881 filter : function(property, value, anyMatch){
7882 var fn = this.createFilterFn(property, value, anyMatch);
7883 return fn ? this.filterBy(fn) : this.clearFilter();
7887 * Filter by a function. The specified function will be called with each
7888 * record in this data source. If the function returns true the record is included,
7889 * otherwise it is filtered.
7890 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7891 * @param {Object} scope (optional) The scope of the function (defaults to this)
7893 filterBy : function(fn, scope){
7894 this.snapshot = this.snapshot || this.data;
7895 this.data = this.queryBy(fn, scope||this);
7896 this.fireEvent("datachanged", this);
7900 * Query the records by a specified property.
7901 * @param {String} field A field on your records
7902 * @param {String/RegExp} value Either a string that the field
7903 * should start with or a RegExp to test against the field
7904 * @param {Boolean} anyMatch True to match any part not just the beginning
7905 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7907 query : function(property, value, anyMatch){
7908 var fn = this.createFilterFn(property, value, anyMatch);
7909 return fn ? this.queryBy(fn) : this.data.clone();
7913 * Query by a function. The specified function will be called with each
7914 * record in this data source. If the function returns true the record is included
7916 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
7917 * @param {Object} scope (optional) The scope of the function (defaults to this)
7918 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
7920 queryBy : function(fn, scope){
7921 var data = this.snapshot || this.data;
7922 return data.filterBy(fn, scope||this);
7926 * Collects unique values for a particular dataIndex from this store.
7927 * @param {String} dataIndex The property to collect
7928 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
7929 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
7930 * @return {Array} An array of the unique values
7932 collect : function(dataIndex, allowNull, bypassFilter){
7933 var d = (bypassFilter === true && this.snapshot) ?
7934 this.snapshot.items : this.data.items;
7935 var v, sv, r = [], l = {};
7936 for(var i = 0, len = d.length; i < len; i++){
7937 v = d[i].data[dataIndex];
7939 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
7948 * Revert to a view of the Record cache with no filtering applied.
7949 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
7951 clearFilter : function(suppressEvent){
7952 if(this.snapshot && this.snapshot != this.data){
7953 this.data = this.snapshot;
7954 delete this.snapshot;
7955 if(suppressEvent !== true){
7956 this.fireEvent("datachanged", this);
7962 afterEdit : function(record){
7963 if(this.modified.indexOf(record) == -1){
7964 this.modified.push(record);
7966 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
7970 afterReject : function(record){
7971 this.modified.remove(record);
7972 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
7976 afterCommit : function(record){
7977 this.modified.remove(record);
7978 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
7982 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
7983 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
7985 commitChanges : function(){
7986 var m = this.modified.slice(0);
7988 for(var i = 0, len = m.length; i < len; i++){
7994 * Cancel outstanding changes on all changed records.
7996 rejectChanges : function(){
7997 var m = this.modified.slice(0);
7999 for(var i = 0, len = m.length; i < len; i++){
8004 onMetaChange : function(meta, rtype, o){
8005 this.recordType = rtype;
8006 this.fields = rtype.prototype.fields;
8007 delete this.snapshot;
8008 this.sortInfo = meta.sortInfo || this.sortInfo;
8010 this.fireEvent('metachange', this, this.reader.meta);
8013 moveIndex : function(data, type)
8015 var index = this.indexOf(data);
8017 var newIndex = index + type;
8021 this.insert(newIndex, data);
8026 * Ext JS Library 1.1.1
8027 * Copyright(c) 2006-2007, Ext JS, LLC.
8029 * Originally Released Under LGPL - original licence link has changed is not relivant.
8032 * <script type="text/javascript">
8036 * @class Roo.data.SimpleStore
8037 * @extends Roo.data.Store
8038 * Small helper class to make creating Stores from Array data easier.
8039 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
8040 * @cfg {Array} fields An array of field definition objects, or field name strings.
8041 * @cfg {Array} data The multi-dimensional array of data
8043 * @param {Object} config
8045 Roo.data.SimpleStore = function(config){
8046 Roo.data.SimpleStore.superclass.constructor.call(this, {
8048 reader: new Roo.data.ArrayReader({
8051 Roo.data.Record.create(config.fields)
8053 proxy : new Roo.data.MemoryProxy(config.data)
8057 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
8059 * Ext JS Library 1.1.1
8060 * Copyright(c) 2006-2007, Ext JS, LLC.
8062 * Originally Released Under LGPL - original licence link has changed is not relivant.
8065 * <script type="text/javascript">
8070 * @extends Roo.data.Store
8071 * @class Roo.data.JsonStore
8072 * Small helper class to make creating Stores for JSON data easier. <br/>
8074 var store = new Roo.data.JsonStore({
8075 url: 'get-images.php',
8077 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
8080 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
8081 * JsonReader and HttpProxy (unless inline data is provided).</b>
8082 * @cfg {Array} fields An array of field definition objects, or field name strings.
8084 * @param {Object} config
8086 Roo.data.JsonStore = function(c){
8087 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
8088 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
8089 reader: new Roo.data.JsonReader(c, c.fields)
8092 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
8094 * Ext JS Library 1.1.1
8095 * Copyright(c) 2006-2007, Ext JS, LLC.
8097 * Originally Released Under LGPL - original licence link has changed is not relivant.
8100 * <script type="text/javascript">
8104 Roo.data.Field = function(config){
8105 if(typeof config == "string"){
8106 config = {name: config};
8108 Roo.apply(this, config);
8114 var st = Roo.data.SortTypes;
8115 // named sortTypes are supported, here we look them up
8116 if(typeof this.sortType == "string"){
8117 this.sortType = st[this.sortType];
8120 // set default sortType for strings and dates
8124 this.sortType = st.asUCString;
8127 this.sortType = st.asDate;
8130 this.sortType = st.none;
8135 var stripRe = /[\$,%]/g;
8137 // prebuilt conversion function for this field, instead of
8138 // switching every time we're reading a value
8140 var cv, dateFormat = this.dateFormat;
8145 cv = function(v){ return v; };
8148 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
8152 return v !== undefined && v !== null && v !== '' ?
8153 parseInt(String(v).replace(stripRe, ""), 10) : '';
8158 return v !== undefined && v !== null && v !== '' ?
8159 parseFloat(String(v).replace(stripRe, ""), 10) : '';
8164 cv = function(v){ return v === true || v === "true" || v == 1; };
8171 if(v instanceof Date){
8175 if(dateFormat == "timestamp"){
8176 return new Date(v*1000);
8178 return Date.parseDate(v, dateFormat);
8180 var parsed = Date.parse(v);
8181 return parsed ? new Date(parsed) : null;
8190 Roo.data.Field.prototype = {
8198 * Ext JS Library 1.1.1
8199 * Copyright(c) 2006-2007, Ext JS, LLC.
8201 * Originally Released Under LGPL - original licence link has changed is not relivant.
8204 * <script type="text/javascript">
8207 // Base class for reading structured data from a data source. This class is intended to be
8208 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
8211 * @class Roo.data.DataReader
8212 * Base class for reading structured data from a data source. This class is intended to be
8213 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
8216 Roo.data.DataReader = function(meta, recordType){
8220 this.recordType = recordType instanceof Array ?
8221 Roo.data.Record.create(recordType) : recordType;
8224 Roo.data.DataReader.prototype = {
8226 * Create an empty record
8227 * @param {Object} data (optional) - overlay some values
8228 * @return {Roo.data.Record} record created.
8230 newRow : function(d) {
8232 this.recordType.prototype.fields.each(function(c) {
8234 case 'int' : da[c.name] = 0; break;
8235 case 'date' : da[c.name] = new Date(); break;
8236 case 'float' : da[c.name] = 0.0; break;
8237 case 'boolean' : da[c.name] = false; break;
8238 default : da[c.name] = ""; break;
8242 return new this.recordType(Roo.apply(da, d));
8247 * Ext JS Library 1.1.1
8248 * Copyright(c) 2006-2007, Ext JS, LLC.
8250 * Originally Released Under LGPL - original licence link has changed is not relivant.
8253 * <script type="text/javascript">
8257 * @class Roo.data.DataProxy
8258 * @extends Roo.data.Observable
8259 * This class is an abstract base class for implementations which provide retrieval of
8260 * unformatted data objects.<br>
8262 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
8263 * (of the appropriate type which knows how to parse the data object) to provide a block of
8264 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
8266 * Custom implementations must implement the load method as described in
8267 * {@link Roo.data.HttpProxy#load}.
8269 Roo.data.DataProxy = function(){
8273 * Fires before a network request is made to retrieve a data object.
8274 * @param {Object} This DataProxy object.
8275 * @param {Object} params The params parameter to the load function.
8280 * Fires before the load method's callback is called.
8281 * @param {Object} This DataProxy object.
8282 * @param {Object} o The data object.
8283 * @param {Object} arg The callback argument object passed to the load function.
8287 * @event loadexception
8288 * Fires if an Exception occurs during data retrieval.
8289 * @param {Object} This DataProxy object.
8290 * @param {Object} o The data object.
8291 * @param {Object} arg The callback argument object passed to the load function.
8292 * @param {Object} e The Exception.
8294 loadexception : true
8296 Roo.data.DataProxy.superclass.constructor.call(this);
8299 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
8302 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
8306 * Ext JS Library 1.1.1
8307 * Copyright(c) 2006-2007, Ext JS, LLC.
8309 * Originally Released Under LGPL - original licence link has changed is not relivant.
8312 * <script type="text/javascript">
8315 * @class Roo.data.MemoryProxy
8316 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
8317 * to the Reader when its load method is called.
8319 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
8321 Roo.data.MemoryProxy = function(data){
8325 Roo.data.MemoryProxy.superclass.constructor.call(this);
8329 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
8331 * Load data from the requested source (in this case an in-memory
8332 * data object passed to the constructor), read the data object into
8333 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8334 * process that block using the passed callback.
8335 * @param {Object} params This parameter is not used by the MemoryProxy class.
8336 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8337 * object into a block of Roo.data.Records.
8338 * @param {Function} callback The function into which to pass the block of Roo.data.records.
8339 * The function must be passed <ul>
8340 * <li>The Record block object</li>
8341 * <li>The "arg" argument from the load function</li>
8342 * <li>A boolean success indicator</li>
8344 * @param {Object} scope The scope in which to call the callback
8345 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8347 load : function(params, reader, callback, scope, arg){
8348 params = params || {};
8351 result = reader.readRecords(this.data);
8353 this.fireEvent("loadexception", this, arg, null, e);
8354 callback.call(scope, null, arg, false);
8357 callback.call(scope, result, arg, true);
8361 update : function(params, records){
8366 * Ext JS Library 1.1.1
8367 * Copyright(c) 2006-2007, Ext JS, LLC.
8369 * Originally Released Under LGPL - original licence link has changed is not relivant.
8372 * <script type="text/javascript">
8375 * @class Roo.data.HttpProxy
8376 * @extends Roo.data.DataProxy
8377 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
8378 * configured to reference a certain URL.<br><br>
8380 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
8381 * from which the running page was served.<br><br>
8383 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
8385 * Be aware that to enable the browser to parse an XML document, the server must set
8386 * the Content-Type header in the HTTP response to "text/xml".
8388 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
8389 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
8390 * will be used to make the request.
8392 Roo.data.HttpProxy = function(conn){
8393 Roo.data.HttpProxy.superclass.constructor.call(this);
8394 // is conn a conn config or a real conn?
8396 this.useAjax = !conn || !conn.events;
8400 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
8401 // thse are take from connection...
8404 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
8407 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
8408 * extra parameters to each request made by this object. (defaults to undefined)
8411 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
8412 * to each request made by this object. (defaults to undefined)
8415 * @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)
8418 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
8421 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
8427 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
8431 * Return the {@link Roo.data.Connection} object being used by this Proxy.
8432 * @return {Connection} The Connection object. This object may be used to subscribe to events on
8433 * a finer-grained basis than the DataProxy events.
8435 getConnection : function(){
8436 return this.useAjax ? Roo.Ajax : this.conn;
8440 * Load data from the configured {@link Roo.data.Connection}, read the data object into
8441 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
8442 * process that block using the passed callback.
8443 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8444 * for the request to the remote server.
8445 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8446 * object into a block of Roo.data.Records.
8447 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8448 * The function must be passed <ul>
8449 * <li>The Record block object</li>
8450 * <li>The "arg" argument from the load function</li>
8451 * <li>A boolean success indicator</li>
8453 * @param {Object} scope The scope in which to call the callback
8454 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8456 load : function(params, reader, callback, scope, arg){
8457 if(this.fireEvent("beforeload", this, params) !== false){
8459 params : params || {},
8461 callback : callback,
8466 callback : this.loadResponse,
8470 Roo.applyIf(o, this.conn);
8471 if(this.activeRequest){
8472 Roo.Ajax.abort(this.activeRequest);
8474 this.activeRequest = Roo.Ajax.request(o);
8476 this.conn.request(o);
8479 callback.call(scope||this, null, arg, false);
8484 loadResponse : function(o, success, response){
8485 delete this.activeRequest;
8487 this.fireEvent("loadexception", this, o, response);
8488 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8493 result = o.reader.read(response);
8495 this.fireEvent("loadexception", this, o, response, e);
8496 o.request.callback.call(o.request.scope, null, o.request.arg, false);
8500 this.fireEvent("load", this, o, o.request.arg);
8501 o.request.callback.call(o.request.scope, result, o.request.arg, true);
8505 update : function(dataSet){
8510 updateResponse : function(dataSet){
8515 * Ext JS Library 1.1.1
8516 * Copyright(c) 2006-2007, Ext JS, LLC.
8518 * Originally Released Under LGPL - original licence link has changed is not relivant.
8521 * <script type="text/javascript">
8525 * @class Roo.data.ScriptTagProxy
8526 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
8527 * other than the originating domain of the running page.<br><br>
8529 * <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
8530 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
8532 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
8533 * source code that is used as the source inside a <script> tag.<br><br>
8535 * In order for the browser to process the returned data, the server must wrap the data object
8536 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
8537 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
8538 * depending on whether the callback name was passed:
8541 boolean scriptTag = false;
8542 String cb = request.getParameter("callback");
8545 response.setContentType("text/javascript");
8547 response.setContentType("application/x-json");
8549 Writer out = response.getWriter();
8551 out.write(cb + "(");
8553 out.print(dataBlock.toJsonString());
8560 * @param {Object} config A configuration object.
8562 Roo.data.ScriptTagProxy = function(config){
8563 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
8564 Roo.apply(this, config);
8565 this.head = document.getElementsByTagName("head")[0];
8568 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
8570 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
8572 * @cfg {String} url The URL from which to request the data object.
8575 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
8579 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
8580 * the server the name of the callback function set up by the load call to process the returned data object.
8581 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
8582 * javascript output which calls this named function passing the data object as its only parameter.
8584 callbackParam : "callback",
8586 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
8587 * name to the request.
8592 * Load data from the configured URL, read the data object into
8593 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
8594 * process that block using the passed callback.
8595 * @param {Object} params An object containing properties which are to be used as HTTP parameters
8596 * for the request to the remote server.
8597 * @param {Roo.data.DataReader} reader The Reader object which converts the data
8598 * object into a block of Roo.data.Records.
8599 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
8600 * The function must be passed <ul>
8601 * <li>The Record block object</li>
8602 * <li>The "arg" argument from the load function</li>
8603 * <li>A boolean success indicator</li>
8605 * @param {Object} scope The scope in which to call the callback
8606 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
8608 load : function(params, reader, callback, scope, arg){
8609 if(this.fireEvent("beforeload", this, params) !== false){
8611 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
8614 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
8616 url += "&_dc=" + (new Date().getTime());
8618 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
8621 cb : "stcCallback"+transId,
8622 scriptId : "stcScript"+transId,
8626 callback : callback,
8632 window[trans.cb] = function(o){
8633 conn.handleResponse(o, trans);
8636 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
8638 if(this.autoAbort !== false){
8642 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
8644 var script = document.createElement("script");
8645 script.setAttribute("src", url);
8646 script.setAttribute("type", "text/javascript");
8647 script.setAttribute("id", trans.scriptId);
8648 this.head.appendChild(script);
8652 callback.call(scope||this, null, arg, false);
8657 isLoading : function(){
8658 return this.trans ? true : false;
8662 * Abort the current server request.
8665 if(this.isLoading()){
8666 this.destroyTrans(this.trans);
8671 destroyTrans : function(trans, isLoaded){
8672 this.head.removeChild(document.getElementById(trans.scriptId));
8673 clearTimeout(trans.timeoutId);
8675 window[trans.cb] = undefined;
8677 delete window[trans.cb];
8680 // if hasn't been loaded, wait for load to remove it to prevent script error
8681 window[trans.cb] = function(){
8682 window[trans.cb] = undefined;
8684 delete window[trans.cb];
8691 handleResponse : function(o, trans){
8693 this.destroyTrans(trans, true);
8696 result = trans.reader.readRecords(o);
8698 this.fireEvent("loadexception", this, o, trans.arg, e);
8699 trans.callback.call(trans.scope||window, null, trans.arg, false);
8702 this.fireEvent("load", this, o, trans.arg);
8703 trans.callback.call(trans.scope||window, result, trans.arg, true);
8707 handleFailure : function(trans){
8709 this.destroyTrans(trans, false);
8710 this.fireEvent("loadexception", this, null, trans.arg);
8711 trans.callback.call(trans.scope||window, null, trans.arg, false);
8715 * Ext JS Library 1.1.1
8716 * Copyright(c) 2006-2007, Ext JS, LLC.
8718 * Originally Released Under LGPL - original licence link has changed is not relivant.
8721 * <script type="text/javascript">
8725 * @class Roo.data.JsonReader
8726 * @extends Roo.data.DataReader
8727 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
8728 * based on mappings in a provided Roo.data.Record constructor.
8730 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
8731 * in the reply previously.
8736 var RecordDef = Roo.data.Record.create([
8737 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
8738 {name: 'occupation'} // This field will use "occupation" as the mapping.
8740 var myReader = new Roo.data.JsonReader({
8741 totalProperty: "results", // The property which contains the total dataset size (optional)
8742 root: "rows", // The property which contains an Array of row objects
8743 id: "id" // The property within each row object that provides an ID for the record (optional)
8747 * This would consume a JSON file like this:
8749 { 'results': 2, 'rows': [
8750 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
8751 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
8754 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
8755 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
8756 * paged from the remote server.
8757 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
8758 * @cfg {String} root name of the property which contains the Array of row objects.
8759 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
8761 * Create a new JsonReader
8762 * @param {Object} meta Metadata configuration options
8763 * @param {Object} recordType Either an Array of field definition objects,
8764 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
8766 Roo.data.JsonReader = function(meta, recordType){
8769 // set some defaults:
8771 totalProperty: 'total',
8772 successProperty : 'success',
8777 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
8779 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
8782 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
8783 * Used by Store query builder to append _requestMeta to params.
8786 metaFromRemote : false,
8788 * This method is only used by a DataProxy which has retrieved data from a remote server.
8789 * @param {Object} response The XHR object which contains the JSON data in its responseText.
8790 * @return {Object} data A data block which is used by an Roo.data.Store object as
8791 * a cache of Roo.data.Records.
8793 read : function(response){
8794 var json = response.responseText;
8796 var o = /* eval:var:o */ eval("("+json+")");
8798 throw {message: "JsonReader.read: Json object not found"};
8804 this.metaFromRemote = true;
8805 this.meta = o.metaData;
8806 this.recordType = Roo.data.Record.create(o.metaData.fields);
8807 this.onMetaChange(this.meta, this.recordType, o);
8809 return this.readRecords(o);
8812 // private function a store will implement
8813 onMetaChange : function(meta, recordType, o){
8820 simpleAccess: function(obj, subsc) {
8827 getJsonAccessor: function(){
8829 return function(expr) {
8831 return(re.test(expr))
8832 ? new Function("obj", "return obj." + expr)
8842 * Create a data block containing Roo.data.Records from an XML document.
8843 * @param {Object} o An object which contains an Array of row objects in the property specified
8844 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
8845 * which contains the total size of the dataset.
8846 * @return {Object} data A data block which is used by an Roo.data.Store object as
8847 * a cache of Roo.data.Records.
8849 readRecords : function(o){
8851 * After any data loads, the raw JSON data is available for further custom processing.
8855 var s = this.meta, Record = this.recordType,
8856 f = Record.prototype.fields, fi = f.items, fl = f.length;
8858 // Generate extraction functions for the totalProperty, the root, the id, and for each field
8860 if(s.totalProperty) {
8861 this.getTotal = this.getJsonAccessor(s.totalProperty);
8863 if(s.successProperty) {
8864 this.getSuccess = this.getJsonAccessor(s.successProperty);
8866 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
8868 var g = this.getJsonAccessor(s.id);
8869 this.getId = function(rec) {
8871 return (r === undefined || r === "") ? null : r;
8874 this.getId = function(){return null;};
8877 for(var jj = 0; jj < fl; jj++){
8879 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
8880 this.ef[jj] = this.getJsonAccessor(map);
8884 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
8885 if(s.totalProperty){
8886 var vt = parseInt(this.getTotal(o), 10);
8891 if(s.successProperty){
8892 var vs = this.getSuccess(o);
8893 if(vs === false || vs === 'false'){
8898 for(var i = 0; i < c; i++){
8901 var id = this.getId(n);
8902 for(var j = 0; j < fl; j++){
8904 var v = this.ef[j](n);
8906 Roo.log('missing convert for ' + f.name);
8910 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
8912 var record = new Record(values, id);
8914 records[i] = record;
8920 totalRecords : totalRecords
8925 * Ext JS Library 1.1.1
8926 * Copyright(c) 2006-2007, Ext JS, LLC.
8928 * Originally Released Under LGPL - original licence link has changed is not relivant.
8931 * <script type="text/javascript">
8935 * @class Roo.data.ArrayReader
8936 * @extends Roo.data.DataReader
8937 * Data reader class to create an Array of Roo.data.Record objects from an Array.
8938 * Each element of that Array represents a row of data fields. The
8939 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
8940 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
8944 var RecordDef = Roo.data.Record.create([
8945 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
8946 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
8948 var myReader = new Roo.data.ArrayReader({
8949 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
8953 * This would consume an Array like this:
8955 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
8957 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
8959 * Create a new JsonReader
8960 * @param {Object} meta Metadata configuration options.
8961 * @param {Object} recordType Either an Array of field definition objects
8962 * as specified to {@link Roo.data.Record#create},
8963 * or an {@link Roo.data.Record} object
8964 * created using {@link Roo.data.Record#create}.
8966 Roo.data.ArrayReader = function(meta, recordType){
8967 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
8970 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
8972 * Create a data block containing Roo.data.Records from an XML document.
8973 * @param {Object} o An Array of row objects which represents the dataset.
8974 * @return {Object} data A data block which is used by an Roo.data.Store object as
8975 * a cache of Roo.data.Records.
8977 readRecords : function(o){
8978 var sid = this.meta ? this.meta.id : null;
8979 var recordType = this.recordType, fields = recordType.prototype.fields;
8982 for(var i = 0; i < root.length; i++){
8985 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
8986 for(var j = 0, jlen = fields.length; j < jlen; j++){
8987 var f = fields.items[j];
8988 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
8989 var v = n[k] !== undefined ? n[k] : f.defaultValue;
8993 var record = new recordType(values, id);
8995 records[records.length] = record;
8999 totalRecords : records.length
9008 * @class Roo.bootstrap.ComboBox
9009 * @extends Roo.bootstrap.TriggerField
9010 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
9011 * @cfg {Boolean} append (true|false) default false
9013 * Create a new ComboBox.
9014 * @param {Object} config Configuration options
9016 Roo.bootstrap.ComboBox = function(config){
9017 Roo.bootstrap.ComboBox.superclass.constructor.call(this, config);
9021 * Fires when the dropdown list is expanded
9022 * @param {Roo.bootstrap.ComboBox} combo This combo box
9027 * Fires when the dropdown list is collapsed
9028 * @param {Roo.bootstrap.ComboBox} combo This combo box
9032 * @event beforeselect
9033 * Fires before a list item is selected. Return false to cancel the selection.
9034 * @param {Roo.bootstrap.ComboBox} combo This combo box
9035 * @param {Roo.data.Record} record The data record returned from the underlying store
9036 * @param {Number} index The index of the selected item in the dropdown list
9038 'beforeselect' : true,
9041 * Fires when a list item is selected
9042 * @param {Roo.bootstrap.ComboBox} combo This combo box
9043 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
9044 * @param {Number} index The index of the selected item in the dropdown list
9048 * @event beforequery
9049 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
9050 * The event object passed has these properties:
9051 * @param {Roo.bootstrap.ComboBox} combo This combo box
9052 * @param {String} query The query
9053 * @param {Boolean} forceAll true to force "all" query
9054 * @param {Boolean} cancel true to cancel the query
9055 * @param {Object} e The query event object
9057 'beforequery': true,
9060 * Fires when the 'add' icon is pressed (add a listener to enable add button)
9061 * @param {Roo.bootstrap.ComboBox} combo This combo box
9066 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
9067 * @param {Roo.bootstrap.ComboBox} combo This combo box
9068 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
9073 * Fires when the remove value from the combobox array
9074 * @param {Roo.bootstrap.ComboBox} combo This combo box
9081 this.selectedIndex = -1;
9082 if(this.mode == 'local'){
9083 if(config.queryDelay === undefined){
9084 this.queryDelay = 10;
9086 if(config.minChars === undefined){
9092 Roo.extend(Roo.bootstrap.ComboBox, Roo.bootstrap.TriggerField, {
9095 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
9096 * rendering into an Roo.Editor, defaults to false)
9099 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
9100 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
9103 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
9106 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
9107 * the dropdown list (defaults to undefined, with no header element)
9111 * @cfg {String/Roo.Template} tpl The template to use to render the output
9115 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
9117 listWidth: undefined,
9119 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
9120 * mode = 'remote' or 'text' if mode = 'local')
9122 displayField: undefined,
9124 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
9125 * mode = 'remote' or 'value' if mode = 'local').
9126 * Note: use of a valueField requires the user make a selection
9127 * in order for a value to be mapped.
9129 valueField: undefined,
9133 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
9134 * field's data value (defaults to the underlying DOM element's name)
9136 hiddenName: undefined,
9138 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
9142 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
9144 selectedClass: 'active',
9147 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
9151 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
9152 * anchor positions (defaults to 'tl-bl')
9154 listAlign: 'tl-bl?',
9156 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
9160 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
9161 * query specified by the allQuery config option (defaults to 'query')
9163 triggerAction: 'query',
9165 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
9166 * (defaults to 4, does not apply if editable = false)
9170 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
9171 * delay (typeAheadDelay) if it matches a known value (defaults to false)
9175 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
9176 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
9180 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
9181 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
9185 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
9186 * when editable = true (defaults to false)
9188 selectOnFocus:false,
9190 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
9192 queryParam: 'query',
9194 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
9195 * when mode = 'remote' (defaults to 'Loading...')
9197 loadingText: 'Loading...',
9199 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
9203 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
9207 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
9208 * traditional select (defaults to true)
9212 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
9216 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
9220 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
9221 * listWidth has a higher value)
9225 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
9226 * allow the user to set arbitrary text into the field (defaults to false)
9228 forceSelection:false,
9230 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
9231 * if typeAhead = true (defaults to 250)
9233 typeAheadDelay : 250,
9235 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
9236 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
9238 valueNotFoundText : undefined,
9240 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
9245 * @cfg {Boolean} disableClear Disable showing of clear button.
9247 disableClear : false,
9249 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
9251 alwaysQuery : false,
9254 * @cfg {Boolean} multiple (true|false) ComboBobArray, default false
9268 // element that contains real text value.. (when hidden is used..)
9271 initEvents: function(){
9274 throw "can not find store for combo";
9276 this.store = Roo.factory(this.store, Roo.data);
9280 Roo.bootstrap.ComboBox.superclass.initEvents.call(this);
9283 if(this.hiddenName){
9285 this.hiddenField = this.el.select('input.form-hidden-field',true).first();
9287 this.hiddenField.dom.value =
9288 this.hiddenValue !== undefined ? this.hiddenValue :
9289 this.value !== undefined ? this.value : '';
9291 // prevent input submission
9292 this.el.dom.removeAttribute('name');
9293 this.hiddenField.dom.setAttribute('name', this.hiddenName);
9298 // this.el.dom.setAttribute('autocomplete', 'off');
9301 var cls = 'x-combo-list';
9302 this.list = this.el.select('ul.dropdown-menu',true).first();
9304 //this.list = new Roo.Layer({
9305 // shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
9308 var lw = this.listWidth || Math.max(this.inputEl().getWidth(), this.minListWidth);
9309 this.list.setWidth(lw);
9311 this.list.on('mouseover', this.onViewOver, this);
9312 this.list.on('mousemove', this.onViewMove, this);
9314 this.list.on('scroll', this.onViewScroll, this);
9317 this.list.swallowEvent('mousewheel');
9318 this.assetHeight = 0;
9321 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
9322 this.assetHeight += this.header.getHeight();
9325 this.innerList = this.list.createChild({cls:cls+'-inner'});
9326 this.innerList.on('mouseover', this.onViewOver, this);
9327 this.innerList.on('mousemove', this.onViewMove, this);
9328 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9330 if(this.allowBlank && !this.pageSize && !this.disableClear){
9331 this.footer = this.list.createChild({cls:cls+'-ft'});
9332 this.pageTb = new Roo.Toolbar(this.footer);
9336 this.footer = this.list.createChild({cls:cls+'-ft'});
9337 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
9338 {pageSize: this.pageSize});
9342 if (this.pageTb && this.allowBlank && !this.disableClear) {
9344 this.pageTb.add(new Roo.Toolbar.Fill(), {
9345 cls: 'x-btn-icon x-btn-clear',
9351 _this.onSelect(false, -1);
9356 this.assetHeight += this.footer.getHeight();
9361 this.tpl = '<li><a href="#">{' + this.displayField + '}</a></li>';
9364 this.view = new Roo.View(this.el.select('ul.dropdown-menu',true).first(), this.tpl, {
9365 singleSelect:true, store: this.store, selectedClass: this.selectedClass
9367 //this.view.wrapEl.setDisplayed(false);
9368 this.view.on('click', this.onViewClick, this);
9372 this.store.on('beforeload', this.onBeforeLoad, this);
9373 this.store.on('load', this.onLoad, this);
9374 this.store.on('loadexception', this.onLoadException, this);
9377 this.resizer = new Roo.Resizable(this.list, {
9378 pinned:true, handles:'se'
9380 this.resizer.on('resize', function(r, w, h){
9381 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
9383 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
9384 this.restrictHeight();
9386 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
9390 this.editable = true;
9391 this.setEditable(false);
9396 if (typeof(this.events.add.listeners) != 'undefined') {
9398 this.addicon = this.wrap.createChild(
9399 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
9401 this.addicon.on('click', function(e) {
9402 this.fireEvent('add', this);
9405 if (typeof(this.events.edit.listeners) != 'undefined') {
9407 this.editicon = this.wrap.createChild(
9408 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
9410 this.editicon.setStyle('margin-left', '40px');
9412 this.editicon.on('click', function(e) {
9414 // we fire even if inothing is selected..
9415 this.fireEvent('edit', this, this.lastData );
9421 this.keyNav = new Roo.KeyNav(this.inputEl(), {
9423 this.inKeyMode = true;
9427 "down" : function(e){
9428 if(!this.isExpanded()){
9429 this.onTriggerClick();
9431 this.inKeyMode = true;
9436 "enter" : function(e){
9441 "esc" : function(e){
9445 "tab" : function(e){
9448 if(this.fireEvent("specialkey", this, e)){
9449 this.onViewClick(false);
9457 doRelay : function(foo, bar, hname){
9458 if(hname == 'down' || this.scope.isExpanded()){
9459 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
9468 this.queryDelay = Math.max(this.queryDelay || 10,
9469 this.mode == 'local' ? 10 : 250);
9472 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
9475 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
9477 if(this.editable !== false){
9478 this.inputEl().on("keyup", this.onKeyUp, this);
9480 if(this.forceSelection){
9481 this.on('blur', this.doForce, this);
9485 this.choices = this.el.select('ul.select2-choices', true).first();
9486 this.searchField = this.el.select('ul li.select2-search-field', true).first();
9490 onDestroy : function(){
9492 this.view.setStore(null);
9493 this.view.el.removeAllListeners();
9494 this.view.el.remove();
9495 this.view.purgeListeners();
9498 this.list.dom.innerHTML = '';
9501 this.store.un('beforeload', this.onBeforeLoad, this);
9502 this.store.un('load', this.onLoad, this);
9503 this.store.un('loadexception', this.onLoadException, this);
9505 Roo.bootstrap.ComboBox.superclass.onDestroy.call(this);
9509 fireKey : function(e){
9510 if(e.isNavKeyPress() && !this.list.isVisible()){
9511 this.fireEvent("specialkey", this, e);
9516 onResize: function(w, h){
9517 // Roo.bootstrap.ComboBox.superclass.onResize.apply(this, arguments);
9519 // if(typeof w != 'number'){
9520 // // we do not handle it!?!?
9523 // var tw = this.trigger.getWidth();
9524 // // tw += this.addicon ? this.addicon.getWidth() : 0;
9525 // // tw += this.editicon ? this.editicon.getWidth() : 0;
9527 // this.inputEl().setWidth( this.adjustWidth('input', x));
9529 // //this.trigger.setStyle('left', x+'px');
9531 // if(this.list && this.listWidth === undefined){
9532 // var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
9533 // this.list.setWidth(lw);
9534 // this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
9542 * Allow or prevent the user from directly editing the field text. If false is passed,
9543 * the user will only be able to select from the items defined in the dropdown list. This method
9544 * is the runtime equivalent of setting the 'editable' config option at config time.
9545 * @param {Boolean} value True to allow the user to directly edit the field text
9547 setEditable : function(value){
9548 if(value == this.editable){
9551 this.editable = value;
9553 this.inputEl().dom.setAttribute('readOnly', true);
9554 this.inputEl().on('mousedown', this.onTriggerClick, this);
9555 this.inputEl().addClass('x-combo-noedit');
9557 this.inputEl().dom.setAttribute('readOnly', false);
9558 this.inputEl().un('mousedown', this.onTriggerClick, this);
9559 this.inputEl().removeClass('x-combo-noedit');
9565 onBeforeLoad : function(combo,opts){
9570 this.list.dom.innerHTML = '<li class="loading-indicator">'+(this.loadingText||'loading')+'</li>' ;
9572 this.restrictHeight();
9573 this.selectedIndex = -1;
9577 onLoad : function(){
9579 this.hasQuery = false;
9585 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9586 this.loading.hide();
9589 if(this.store.getCount() > 0){
9591 this.restrictHeight();
9592 if(this.lastQuery == this.allQuery){
9594 this.inputEl().dom.select();
9596 if(!this.selectByValue(this.value, true)){
9597 this.select(0, true);
9601 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
9602 this.taTask.delay(this.typeAheadDelay);
9606 this.onEmptyResults();
9612 onLoadException : function()
9614 this.hasQuery = false;
9616 if(typeof(this.loading) !== 'undefined' && this.loading !== null){
9617 this.loading.hide();
9621 Roo.log(this.store.reader.jsonData);
9622 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
9624 //Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
9630 onTypeAhead : function(){
9631 if(this.store.getCount() > 0){
9632 var r = this.store.getAt(0);
9633 var newValue = r.data[this.displayField];
9634 var len = newValue.length;
9635 var selStart = this.getRawValue().length;
9637 if(selStart != len){
9638 this.setRawValue(newValue);
9639 this.selectText(selStart, newValue.length);
9645 onSelect : function(record, index){
9647 if(this.fireEvent('beforeselect', this, record, index) !== false){
9649 this.setFromData(index > -1 ? record.data : false);
9652 this.fireEvent('select', this, record, index);
9657 * Returns the currently selected field value or empty string if no value is set.
9658 * @return {String} value The selected value
9660 getValue : function(){
9663 return (this.hiddenField) ? this.hiddenField.dom.value : this.value;
9666 if(this.valueField){
9667 return typeof this.value != 'undefined' ? this.value : '';
9669 return Roo.bootstrap.ComboBox.superclass.getValue.call(this);
9674 * Clears any text/value currently set in the field
9676 clearValue : function(){
9677 if(this.hiddenField){
9678 this.hiddenField.dom.value = '';
9681 this.setRawValue('');
9682 this.lastSelectionText = '';
9687 * Sets the specified value into the field. If the value finds a match, the corresponding record text
9688 * will be displayed in the field. If the value does not match the data value of an existing item,
9689 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
9690 * Otherwise the field will be blank (although the value will still be set).
9691 * @param {String} value The value to match
9693 setValue : function(v){
9700 if(this.valueField){
9701 var r = this.findRecord(this.valueField, v);
9703 text = r.data[this.displayField];
9704 }else if(this.valueNotFoundText !== undefined){
9705 text = this.valueNotFoundText;
9708 this.lastSelectionText = text;
9709 if(this.hiddenField){
9710 this.hiddenField.dom.value = v;
9712 Roo.bootstrap.ComboBox.superclass.setValue.call(this, text);
9716 * @property {Object} the last set data for the element
9721 * Sets the value of the field based on a object which is related to the record format for the store.
9722 * @param {Object} value the value to set as. or false on reset?
9724 setFromData : function(o){
9731 var dv = ''; // display value
9732 var vv = ''; // value value..
9734 if (this.displayField) {
9735 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
9737 // this is an error condition!!!
9738 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
9741 if(this.valueField){
9742 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
9745 if(this.hiddenField){
9746 this.hiddenField.dom.value = vv;
9748 this.lastSelectionText = dv;
9749 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9753 // no hidden field.. - we store the value in 'value', but still display
9754 // display field!!!!
9755 this.lastSelectionText = dv;
9756 Roo.bootstrap.ComboBox.superclass.setValue.call(this, dv);
9763 // overridden so that last data is reset..
9764 this.setValue(this.originalValue);
9765 this.clearInvalid();
9766 this.lastData = false;
9768 this.view.clearSelections();
9772 findRecord : function(prop, value){
9774 if(this.store.getCount() > 0){
9775 this.store.each(function(r){
9776 if(r.data[prop] == value){
9788 // returns hidden if it's set..
9789 if (!this.rendered) {return ''};
9790 return !this.hiddenName && this.inputEl().dom.name ? this.inputEl().dom.name : (this.hiddenName || '');
9794 onViewMove : function(e, t){
9795 this.inKeyMode = false;
9799 onViewOver : function(e, t){
9800 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
9803 var item = this.view.findItemFromChild(t);
9805 var index = this.view.indexOf(item);
9806 this.select(index, false);
9811 onViewClick : function(doFocus)
9813 var index = this.view.getSelectedIndexes()[0];
9814 var r = this.store.getAt(index);
9816 this.onSelect(r, index);
9818 if(doFocus !== false && !this.blockFocus){
9819 this.inputEl().focus();
9824 restrictHeight : function(){
9825 //this.innerList.dom.style.height = '';
9826 //var inner = this.innerList.dom;
9827 //var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
9828 //this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
9829 //this.list.beginUpdate();
9830 //this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
9831 this.list.alignTo(this.inputEl(), this.listAlign);
9832 //this.list.endUpdate();
9836 onEmptyResults : function(){
9841 * Returns true if the dropdown list is expanded, else false.
9843 isExpanded : function(){
9844 return this.list.isVisible();
9848 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
9849 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9850 * @param {String} value The data value of the item to select
9851 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9852 * selected item if it is not currently in view (defaults to true)
9853 * @return {Boolean} True if the value matched an item in the list, else false
9855 selectByValue : function(v, scrollIntoView){
9856 if(v !== undefined && v !== null){
9857 var r = this.findRecord(this.valueField || this.displayField, v);
9859 this.select(this.store.indexOf(r), scrollIntoView);
9867 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
9868 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
9869 * @param {Number} index The zero-based index of the list item to select
9870 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
9871 * selected item if it is not currently in view (defaults to true)
9873 select : function(index, scrollIntoView){
9874 this.selectedIndex = index;
9875 this.view.select(index);
9876 if(scrollIntoView !== false){
9877 var el = this.view.getNode(index);
9879 //this.innerList.scrollChildIntoView(el, false);
9886 selectNext : function(){
9887 var ct = this.store.getCount();
9889 if(this.selectedIndex == -1){
9891 }else if(this.selectedIndex < ct-1){
9892 this.select(this.selectedIndex+1);
9898 selectPrev : function(){
9899 var ct = this.store.getCount();
9901 if(this.selectedIndex == -1){
9903 }else if(this.selectedIndex != 0){
9904 this.select(this.selectedIndex-1);
9910 onKeyUp : function(e){
9911 if(this.editable !== false && !e.isSpecialKey()){
9912 this.lastKey = e.getKey();
9913 this.dqTask.delay(this.queryDelay);
9918 validateBlur : function(){
9919 return !this.list || !this.list.isVisible();
9923 initQuery : function(){
9924 this.doQuery(this.getRawValue());
9928 doForce : function(){
9929 if(this.el.dom.value.length > 0){
9931 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
9937 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
9938 * query allowing the query action to be canceled if needed.
9939 * @param {String} query The SQL query to execute
9940 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
9941 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
9942 * saved in the current store (defaults to false)
9944 doQuery : function(q, forceAll){
9946 if(q === undefined || q === null){
9955 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
9960 forceAll = qe.forceAll;
9961 if(forceAll === true || (q.length >= this.minChars)){
9963 this.hasQuery = true;
9965 if(this.lastQuery != q || this.alwaysQuery){
9967 if(this.mode == 'local'){
9968 this.selectedIndex = -1;
9970 this.store.clearFilter();
9972 this.store.filter(this.displayField, q);
9976 this.store.baseParams[this.queryParam] = q;
9978 var options = {params : this.getParams(q)};
9982 options.params.start = this.page * this.pageSize;
9985 this.store.load(options);
9989 this.selectedIndex = -1;
9994 this.loadNext = false;
9998 getParams : function(q){
10000 //p[this.queryParam] = q;
10004 p.limit = this.pageSize;
10010 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
10012 collapse : function(){
10013 if(!this.isExpanded()){
10018 Roo.get(document).un('mousedown', this.collapseIf, this);
10019 Roo.get(document).un('mousewheel', this.collapseIf, this);
10020 if (!this.editable) {
10021 Roo.get(document).un('keydown', this.listKeyPress, this);
10023 this.fireEvent('collapse', this);
10027 collapseIf : function(e){
10028 var in_combo = e.within(this.el);
10029 var in_list = e.within(this.list);
10031 if (in_combo || in_list) {
10032 //e.stopPropagation();
10041 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
10043 expand : function(){
10045 if(this.isExpanded() || !this.hasFocus){
10049 this.list.alignTo(this.inputEl(), this.listAlign);
10051 Roo.get(document).on('mousedown', this.collapseIf, this);
10052 Roo.get(document).on('mousewheel', this.collapseIf, this);
10053 if (!this.editable) {
10054 Roo.get(document).on('keydown', this.listKeyPress, this);
10057 this.fireEvent('expand', this);
10061 // Implements the default empty TriggerField.onTriggerClick function
10062 onTriggerClick : function()
10064 Roo.log('trigger click');
10071 this.loadNext = false;
10073 if(this.isExpanded()){
10075 if (!this.blockFocus) {
10076 this.inputEl().focus();
10080 this.hasFocus = true;
10081 if(this.triggerAction == 'all') {
10082 this.doQuery(this.allQuery, true);
10084 this.doQuery(this.getRawValue());
10086 if (!this.blockFocus) {
10087 this.inputEl().focus();
10091 listKeyPress : function(e)
10093 //Roo.log('listkeypress');
10094 // scroll to first matching element based on key pres..
10095 if (e.isSpecialKey()) {
10098 var k = String.fromCharCode(e.getKey()).toUpperCase();
10101 var csel = this.view.getSelectedNodes();
10102 var cselitem = false;
10104 var ix = this.view.indexOf(csel[0]);
10105 cselitem = this.store.getAt(ix);
10106 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
10112 this.store.each(function(v) {
10114 // start at existing selection.
10115 if (cselitem.id == v.id) {
10121 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
10122 match = this.store.indexOf(v);
10128 if (match === false) {
10129 return true; // no more action?
10132 this.view.select(match);
10133 var sn = Roo.get(this.view.getSelectedNodes()[0])
10134 //sn.scrollIntoView(sn.dom.parentNode, false);
10137 onViewScroll : function(e, t){
10139 if(this.view.el.getScroll().top < this.view.el.dom.scrollHeight - this.view.el.dom.clientHeight || !this.hasFocus || !this.append || this.hasQuery){
10143 this.hasQuery = true;
10145 this.loading = this.list.select('.loading', true).first();
10147 if(this.loading === null){
10148 this.list.createChild({
10150 cls: 'loading select2-more-results select2-active',
10151 html: 'Loading more results...'
10154 this.loading = this.list.select('.loading', true).first();
10156 this.loading.setVisibilityMode(Roo.Element.DISPLAY);
10158 this.loading.hide();
10161 this.loading.show();
10166 this.loadNext = true;
10168 (function() { _combo.doQuery(_combo.allQuery, true); }).defer(500);
10173 addItem : function(o)
10175 var dv = ''; // display value
10177 if (this.displayField) {
10178 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
10180 // this is an error condition!!!
10181 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
10188 var choice = this.choices.createChild({
10190 cls: 'select2-search-choice',
10199 cls: 'select2-search-choice-close',
10204 }, this.searchField);
10206 var close = choice.select('a.select2-search-choice-close', true).first()
10208 close.on('click', this.onRemoveItem, this, { item : choice, data : o} );
10215 this.inputEl().dom.value = '';
10219 onRemoveItem : function(e, _self, o)
10221 Roo.log('remove item');
10222 var index = this.item.indexOf(o.data) * 1;
10225 Roo.log('not this item?!');
10229 this.item.splice(index, 1);
10234 this.fireEvent('remove', this, e);
10238 syncValue : function()
10240 if(!this.item.length){
10247 Roo.each(this.item, function(i){
10248 if(_this.valueField){
10249 value.push(i[_this.valueField]);
10256 this.value = value.join(',');
10258 if(this.hiddenField){
10259 this.hiddenField.dom.value = this.value;
10263 clearItem : function()
10265 if(!this.multiple){
10271 Roo.each(this.choices.select('>li.select2-search-choice', true).elements, function(c){
10281 * @cfg {Boolean} grow
10285 * @cfg {Number} growMin
10289 * @cfg {Number} growMax
10299 * Ext JS Library 1.1.1
10300 * Copyright(c) 2006-2007, Ext JS, LLC.
10302 * Originally Released Under LGPL - original licence link has changed is not relivant.
10305 * <script type="text/javascript">
10310 * @extends Roo.util.Observable
10311 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
10312 * This class also supports single and multi selection modes. <br>
10313 * Create a data model bound view:
10315 var store = new Roo.data.Store(...);
10317 var view = new Roo.View({
10319 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
10321 singleSelect: true,
10322 selectedClass: "ydataview-selected",
10326 // listen for node click?
10327 view.on("click", function(vw, index, node, e){
10328 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
10332 dataModel.load("foobar.xml");
10334 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
10336 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
10337 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
10339 * Note: old style constructor is still suported (container, template, config)
10342 * Create a new View
10343 * @param {Object} config The config object
10346 Roo.View = function(config, depreciated_tpl, depreciated_config){
10348 if (typeof(depreciated_tpl) == 'undefined') {
10349 // new way.. - universal constructor.
10350 Roo.apply(this, config);
10351 this.el = Roo.get(this.el);
10354 this.el = Roo.get(config);
10355 this.tpl = depreciated_tpl;
10356 Roo.apply(this, depreciated_config);
10358 this.wrapEl = this.el.wrap().wrap();
10359 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
10362 if(typeof(this.tpl) == "string"){
10363 this.tpl = new Roo.Template(this.tpl);
10365 // support xtype ctors..
10366 this.tpl = new Roo.factory(this.tpl, Roo);
10370 this.tpl.compile();
10378 * @event beforeclick
10379 * Fires before a click is processed. Returns false to cancel the default action.
10380 * @param {Roo.View} this
10381 * @param {Number} index The index of the target node
10382 * @param {HTMLElement} node The target node
10383 * @param {Roo.EventObject} e The raw event object
10385 "beforeclick" : true,
10388 * Fires when a template node is clicked.
10389 * @param {Roo.View} this
10390 * @param {Number} index The index of the target node
10391 * @param {HTMLElement} node The target node
10392 * @param {Roo.EventObject} e The raw event object
10397 * Fires when a template node is double clicked.
10398 * @param {Roo.View} this
10399 * @param {Number} index The index of the target node
10400 * @param {HTMLElement} node The target node
10401 * @param {Roo.EventObject} e The raw event object
10405 * @event contextmenu
10406 * Fires when a template node is right clicked.
10407 * @param {Roo.View} this
10408 * @param {Number} index The index of the target node
10409 * @param {HTMLElement} node The target node
10410 * @param {Roo.EventObject} e The raw event object
10412 "contextmenu" : true,
10414 * @event selectionchange
10415 * Fires when the selected nodes change.
10416 * @param {Roo.View} this
10417 * @param {Array} selections Array of the selected nodes
10419 "selectionchange" : true,
10422 * @event beforeselect
10423 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
10424 * @param {Roo.View} this
10425 * @param {HTMLElement} node The node to be selected
10426 * @param {Array} selections Array of currently selected nodes
10428 "beforeselect" : true,
10430 * @event preparedata
10431 * Fires on every row to render, to allow you to change the data.
10432 * @param {Roo.View} this
10433 * @param {Object} data to be rendered (change this)
10435 "preparedata" : true
10443 "click": this.onClick,
10444 "dblclick": this.onDblClick,
10445 "contextmenu": this.onContextMenu,
10449 this.selections = [];
10451 this.cmp = new Roo.CompositeElementLite([]);
10453 this.store = Roo.factory(this.store, Roo.data);
10454 this.setStore(this.store, true);
10457 if ( this.footer && this.footer.xtype) {
10459 var fctr = this.wrapEl.appendChild(document.createElement("div"));
10461 this.footer.dataSource = this.store
10462 this.footer.container = fctr;
10463 this.footer = Roo.factory(this.footer, Roo);
10464 fctr.insertFirst(this.el);
10466 // this is a bit insane - as the paging toolbar seems to detach the el..
10467 // dom.parentNode.parentNode.parentNode
10468 // they get detached?
10472 Roo.View.superclass.constructor.call(this);
10477 Roo.extend(Roo.View, Roo.util.Observable, {
10480 * @cfg {Roo.data.Store} store Data store to load data from.
10485 * @cfg {String|Roo.Element} el The container element.
10490 * @cfg {String|Roo.Template} tpl The template used by this View
10494 * @cfg {String} dataName the named area of the template to use as the data area
10495 * Works with domtemplates roo-name="name"
10499 * @cfg {String} selectedClass The css class to add to selected nodes
10501 selectedClass : "x-view-selected",
10503 * @cfg {String} emptyText The empty text to show when nothing is loaded.
10508 * @cfg {String} text to display on mask (default Loading)
10512 * @cfg {Boolean} multiSelect Allow multiple selection
10514 multiSelect : false,
10516 * @cfg {Boolean} singleSelect Allow single selection
10518 singleSelect: false,
10521 * @cfg {Boolean} toggleSelect - selecting
10523 toggleSelect : false,
10526 * Returns the element this view is bound to.
10527 * @return {Roo.Element}
10529 getEl : function(){
10530 return this.wrapEl;
10536 * Refreshes the view. - called by datachanged on the store. - do not call directly.
10538 refresh : function(){
10539 Roo.log('refresh');
10542 // if we are using something like 'domtemplate', then
10543 // the what gets used is:
10544 // t.applySubtemplate(NAME, data, wrapping data..)
10545 // the outer template then get' applied with
10546 // the store 'extra data'
10547 // and the body get's added to the
10548 // roo-name="data" node?
10549 // <span class='roo-tpl-{name}'></span> ?????
10553 this.clearSelections();
10554 this.el.update("");
10556 var records = this.store.getRange();
10557 if(records.length < 1) {
10559 // is this valid?? = should it render a template??
10561 this.el.update(this.emptyText);
10565 if (this.dataName) {
10566 this.el.update(t.apply(this.store.meta)); //????
10567 el = this.el.child('.roo-tpl-' + this.dataName);
10570 for(var i = 0, len = records.length; i < len; i++){
10571 var data = this.prepareData(records[i].data, i, records[i]);
10572 this.fireEvent("preparedata", this, data, i, records[i]);
10573 html[html.length] = Roo.util.Format.trim(
10575 t.applySubtemplate(this.dataName, data, this.store.meta) :
10582 el.update(html.join(""));
10583 this.nodes = el.dom.childNodes;
10584 this.updateIndexes(0);
10589 * Function to override to reformat the data that is sent to
10590 * the template for each node.
10591 * DEPRICATED - use the preparedata event handler.
10592 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
10593 * a JSON object for an UpdateManager bound view).
10595 prepareData : function(data, index, record)
10597 this.fireEvent("preparedata", this, data, index, record);
10601 onUpdate : function(ds, record){
10602 Roo.log('on update');
10603 this.clearSelections();
10604 var index = this.store.indexOf(record);
10605 var n = this.nodes[index];
10606 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
10607 n.parentNode.removeChild(n);
10608 this.updateIndexes(index, index);
10614 onAdd : function(ds, records, index)
10616 Roo.log(['on Add', ds, records, index] );
10617 this.clearSelections();
10618 if(this.nodes.length == 0){
10622 var n = this.nodes[index];
10623 for(var i = 0, len = records.length; i < len; i++){
10624 var d = this.prepareData(records[i].data, i, records[i]);
10626 this.tpl.insertBefore(n, d);
10629 this.tpl.append(this.el, d);
10632 this.updateIndexes(index);
10635 onRemove : function(ds, record, index){
10636 Roo.log('onRemove');
10637 this.clearSelections();
10638 var el = this.dataName ?
10639 this.el.child('.roo-tpl-' + this.dataName) :
10642 el.dom.removeChild(this.nodes[index]);
10643 this.updateIndexes(index);
10647 * Refresh an individual node.
10648 * @param {Number} index
10650 refreshNode : function(index){
10651 this.onUpdate(this.store, this.store.getAt(index));
10654 updateIndexes : function(startIndex, endIndex){
10655 var ns = this.nodes;
10656 startIndex = startIndex || 0;
10657 endIndex = endIndex || ns.length - 1;
10658 for(var i = startIndex; i <= endIndex; i++){
10659 ns[i].nodeIndex = i;
10664 * Changes the data store this view uses and refresh the view.
10665 * @param {Store} store
10667 setStore : function(store, initial){
10668 if(!initial && this.store){
10669 this.store.un("datachanged", this.refresh);
10670 this.store.un("add", this.onAdd);
10671 this.store.un("remove", this.onRemove);
10672 this.store.un("update", this.onUpdate);
10673 this.store.un("clear", this.refresh);
10674 this.store.un("beforeload", this.onBeforeLoad);
10675 this.store.un("load", this.onLoad);
10676 this.store.un("loadexception", this.onLoad);
10680 store.on("datachanged", this.refresh, this);
10681 store.on("add", this.onAdd, this);
10682 store.on("remove", this.onRemove, this);
10683 store.on("update", this.onUpdate, this);
10684 store.on("clear", this.refresh, this);
10685 store.on("beforeload", this.onBeforeLoad, this);
10686 store.on("load", this.onLoad, this);
10687 store.on("loadexception", this.onLoad, this);
10695 * onbeforeLoad - masks the loading area.
10698 onBeforeLoad : function(store,opts)
10700 Roo.log('onBeforeLoad');
10702 this.el.update("");
10704 this.el.mask(this.mask ? this.mask : "Loading" );
10706 onLoad : function ()
10713 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
10714 * @param {HTMLElement} node
10715 * @return {HTMLElement} The template node
10717 findItemFromChild : function(node){
10718 var el = this.dataName ?
10719 this.el.child('.roo-tpl-' + this.dataName,true) :
10722 if(!node || node.parentNode == el){
10725 var p = node.parentNode;
10726 while(p && p != el){
10727 if(p.parentNode == el){
10736 onClick : function(e){
10737 var item = this.findItemFromChild(e.getTarget());
10739 var index = this.indexOf(item);
10740 if(this.onItemClick(item, index, e) !== false){
10741 this.fireEvent("click", this, index, item, e);
10744 this.clearSelections();
10749 onContextMenu : function(e){
10750 var item = this.findItemFromChild(e.getTarget());
10752 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
10757 onDblClick : function(e){
10758 var item = this.findItemFromChild(e.getTarget());
10760 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
10764 onItemClick : function(item, index, e)
10766 if(this.fireEvent("beforeclick", this, index, item, e) === false){
10769 if (this.toggleSelect) {
10770 var m = this.isSelected(item) ? 'unselect' : 'select';
10773 _t[m](item, true, false);
10776 if(this.multiSelect || this.singleSelect){
10777 if(this.multiSelect && e.shiftKey && this.lastSelection){
10778 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
10780 this.select(item, this.multiSelect && e.ctrlKey);
10781 this.lastSelection = item;
10783 e.preventDefault();
10789 * Get the number of selected nodes.
10792 getSelectionCount : function(){
10793 return this.selections.length;
10797 * Get the currently selected nodes.
10798 * @return {Array} An array of HTMLElements
10800 getSelectedNodes : function(){
10801 return this.selections;
10805 * Get the indexes of the selected nodes.
10808 getSelectedIndexes : function(){
10809 var indexes = [], s = this.selections;
10810 for(var i = 0, len = s.length; i < len; i++){
10811 indexes.push(s[i].nodeIndex);
10817 * Clear all selections
10818 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
10820 clearSelections : function(suppressEvent){
10821 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
10822 this.cmp.elements = this.selections;
10823 this.cmp.removeClass(this.selectedClass);
10824 this.selections = [];
10825 if(!suppressEvent){
10826 this.fireEvent("selectionchange", this, this.selections);
10832 * Returns true if the passed node is selected
10833 * @param {HTMLElement/Number} node The node or node index
10834 * @return {Boolean}
10836 isSelected : function(node){
10837 var s = this.selections;
10841 node = this.getNode(node);
10842 return s.indexOf(node) !== -1;
10847 * @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
10848 * @param {Boolean} keepExisting (optional) true to keep existing selections
10849 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10851 select : function(nodeInfo, keepExisting, suppressEvent){
10852 if(nodeInfo instanceof Array){
10854 this.clearSelections(true);
10856 for(var i = 0, len = nodeInfo.length; i < len; i++){
10857 this.select(nodeInfo[i], true, true);
10861 var node = this.getNode(nodeInfo);
10862 if(!node || this.isSelected(node)){
10863 return; // already selected.
10866 this.clearSelections(true);
10868 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
10869 Roo.fly(node).addClass(this.selectedClass);
10870 this.selections.push(node);
10871 if(!suppressEvent){
10872 this.fireEvent("selectionchange", this, this.selections);
10880 * @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
10881 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
10882 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
10884 unselect : function(nodeInfo, keepExisting, suppressEvent)
10886 if(nodeInfo instanceof Array){
10887 Roo.each(this.selections, function(s) {
10888 this.unselect(s, nodeInfo);
10892 var node = this.getNode(nodeInfo);
10893 if(!node || !this.isSelected(node)){
10894 Roo.log("not selected");
10895 return; // not selected.
10899 Roo.each(this.selections, function(s) {
10901 Roo.fly(node).removeClass(this.selectedClass);
10908 this.selections= ns;
10909 this.fireEvent("selectionchange", this, this.selections);
10913 * Gets a template node.
10914 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10915 * @return {HTMLElement} The node or null if it wasn't found
10917 getNode : function(nodeInfo){
10918 if(typeof nodeInfo == "string"){
10919 return document.getElementById(nodeInfo);
10920 }else if(typeof nodeInfo == "number"){
10921 return this.nodes[nodeInfo];
10927 * Gets a range template nodes.
10928 * @param {Number} startIndex
10929 * @param {Number} endIndex
10930 * @return {Array} An array of nodes
10932 getNodes : function(start, end){
10933 var ns = this.nodes;
10934 start = start || 0;
10935 end = typeof end == "undefined" ? ns.length - 1 : end;
10938 for(var i = start; i <= end; i++){
10942 for(var i = start; i >= end; i--){
10950 * Finds the index of the passed node
10951 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
10952 * @return {Number} The index of the node or -1
10954 indexOf : function(node){
10955 node = this.getNode(node);
10956 if(typeof node.nodeIndex == "number"){
10957 return node.nodeIndex;
10959 var ns = this.nodes;
10960 for(var i = 0, len = ns.length; i < len; i++){
10971 * based on jquery fullcalendar
10975 Roo.bootstrap = Roo.bootstrap || {};
10977 * @class Roo.bootstrap.Calendar
10978 * @extends Roo.bootstrap.Component
10979 * Bootstrap Calendar class
10980 * @cfg {Boolean} loadMask (true|false) default false
10981 * @cfg {Object} header generate the user specific header of the calendar, default false
10984 * Create a new Container
10985 * @param {Object} config The config object
10990 Roo.bootstrap.Calendar = function(config){
10991 Roo.bootstrap.Calendar.superclass.constructor.call(this, config);
10995 * Fires when a date is selected
10996 * @param {DatePicker} this
10997 * @param {Date} date The selected date
11001 * @event monthchange
11002 * Fires when the displayed month changes
11003 * @param {DatePicker} this
11004 * @param {Date} date The selected month
11006 'monthchange': true,
11008 * @event evententer
11009 * Fires when mouse over an event
11010 * @param {Calendar} this
11011 * @param {event} Event
11013 'evententer': true,
11015 * @event eventleave
11016 * Fires when the mouse leaves an
11017 * @param {Calendar} this
11020 'eventleave': true,
11022 * @event eventclick
11023 * Fires when the mouse click an
11024 * @param {Calendar} this
11033 Roo.extend(Roo.bootstrap.Calendar, Roo.bootstrap.Component, {
11036 * @cfg {Number} startDay
11037 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
11045 getAutoCreate : function(){
11048 var fc_button = function(name, corner, style, content ) {
11049 return Roo.apply({},{
11051 cls : 'fc-button fc-button-'+name+' fc-state-default ' +
11053 'fc-corner-' + corner.split(' ').join(' fc-corner-') :
11056 html : '<SPAN class="fc-text-'+style+ '">'+content +'</SPAN>',
11067 style : 'width:100%',
11074 cls : 'fc-header-left',
11076 fc_button('prev', 'left', 'arrow', '‹' ),
11077 fc_button('next', 'right', 'arrow', '›' ),
11078 { tag: 'span', cls: 'fc-header-space' },
11079 fc_button('today', 'left right', '', 'today' ) // neds state disabled..
11087 cls : 'fc-header-center',
11091 cls: 'fc-header-title',
11094 html : 'month / year'
11102 cls : 'fc-header-right',
11104 /* fc_button('month', 'left', '', 'month' ),
11105 fc_button('week', '', '', 'week' ),
11106 fc_button('day', 'right', '', 'day' )
11118 header = this.header;
11121 var cal_heads = function() {
11123 // fixme - handle this.
11125 for (var i =0; i < Date.dayNames.length; i++) {
11126 var d = Date.dayNames[i];
11129 cls : 'fc-day-header fc-' + d.substring(0,3).toLowerCase() + ' fc-widget-header',
11130 html : d.substring(0,3)
11134 ret[0].cls += ' fc-first';
11135 ret[6].cls += ' fc-last';
11138 var cal_cell = function(n) {
11141 cls : 'fc-day fc-'+n + ' fc-widget-content', ///fc-other-month fc-past
11146 cls: 'fc-day-number',
11150 cls: 'fc-day-content',
11154 style: 'position: relative;' // height: 17px;
11166 var cal_rows = function() {
11169 for (var r = 0; r < 6; r++) {
11176 for (var i =0; i < Date.dayNames.length; i++) {
11177 var d = Date.dayNames[i];
11178 row.cn.push(cal_cell(d.substring(0,3).toLowerCase()));
11181 row.cn[0].cls+=' fc-first';
11182 row.cn[0].cn[0].style = 'min-height:90px';
11183 row.cn[6].cls+=' fc-last';
11187 ret[0].cls += ' fc-first';
11188 ret[4].cls += ' fc-prev-last';
11189 ret[5].cls += ' fc-last';
11196 cls: 'fc-border-separate',
11197 style : 'width:100%',
11205 cls : 'fc-first fc-last',
11223 cls : 'fc-content',
11224 style : "position: relative;",
11227 cls : 'fc-view fc-view-month fc-grid',
11228 style : 'position: relative',
11229 unselectable : 'on',
11232 cls : 'fc-event-container',
11233 style : 'position:absolute;z-index:8;top:0;left:0;'
11251 initEvents : function()
11254 throw "can not find store for calendar";
11260 style: "text-align:center",
11264 style: "background-color:white;width:50%;margin:250 auto",
11268 src: rootURL + '/roojs1/images/ux/lightbox/loading.gif'
11279 this.maskEl = Roo.DomHelper.append(this.el.select('.fc-content', true).first(), mark, true);
11281 var size = this.el.select('.fc-content', true).first().getSize();
11282 this.maskEl.setSize(size.width, size.height);
11283 this.maskEl.enableDisplayMode("block");
11284 if(!this.loadMask){
11285 this.maskEl.hide();
11288 this.store = Roo.factory(this.store, Roo.data);
11289 this.store.on('load', this.onLoad, this);
11290 this.store.on('beforeload', this.onBeforeLoad, this);
11294 this.cells = this.el.select('.fc-day',true);
11295 //Roo.log(this.cells);
11296 this.textNodes = this.el.query('.fc-day-number');
11297 this.cells.addClassOnOver('fc-state-hover');
11299 this.el.select('.fc-button-prev',true).on('click', this.showPrevMonth, this);
11300 this.el.select('.fc-button-next',true).on('click', this.showNextMonth, this);
11301 this.el.select('.fc-button-today',true).on('click', this.showToday, this);
11302 this.el.select('.fc-button',true).addClassOnOver('fc-state-hover');
11304 this.on('monthchange', this.onMonthChange, this);
11306 this.update(new Date().clearTime());
11309 resize : function() {
11310 var sz = this.el.getSize();
11312 this.el.select('.fc-day-header',true).setWidth(sz.width / 7);
11313 this.el.select('.fc-day-content div',true).setHeight(34);
11318 showPrevMonth : function(e){
11319 this.update(this.activeDate.add("mo", -1));
11321 showToday : function(e){
11322 this.update(new Date().clearTime());
11325 showNextMonth : function(e){
11326 this.update(this.activeDate.add("mo", 1));
11330 showPrevYear : function(){
11331 this.update(this.activeDate.add("y", -1));
11335 showNextYear : function(){
11336 this.update(this.activeDate.add("y", 1));
11341 update : function(date)
11343 var vd = this.activeDate;
11344 this.activeDate = date;
11345 // if(vd && this.el){
11346 // var t = date.getTime();
11347 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
11348 // Roo.log('using add remove');
11350 // this.fireEvent('monthchange', this, date);
11352 // this.cells.removeClass("fc-state-highlight");
11353 // this.cells.each(function(c){
11354 // if(c.dateValue == t){
11355 // c.addClass("fc-state-highlight");
11356 // setTimeout(function(){
11357 // try{c.dom.firstChild.focus();}catch(e){}
11367 var days = date.getDaysInMonth();
11369 var firstOfMonth = date.getFirstDateOfMonth();
11370 var startingPos = firstOfMonth.getDay()-this.startDay;
11372 if(startingPos < this.startDay){
11376 var pm = date.add(Date.MONTH, -1);
11377 var prevStart = pm.getDaysInMonth()-startingPos;
11379 this.cells = this.el.select('.fc-day',true);
11380 this.textNodes = this.el.query('.fc-day-number');
11381 this.cells.addClassOnOver('fc-state-hover');
11383 var cells = this.cells.elements;
11384 var textEls = this.textNodes;
11386 Roo.each(cells, function(cell){
11387 cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
11390 days += startingPos;
11392 // convert everything to numbers so it's fast
11393 var day = 86400000;
11394 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
11397 //Roo.log(prevStart);
11399 var today = new Date().clearTime().getTime();
11400 var sel = date.clearTime().getTime();
11401 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
11402 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
11403 var ddMatch = this.disabledDatesRE;
11404 var ddText = this.disabledDatesText;
11405 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
11406 var ddaysText = this.disabledDaysText;
11407 var format = this.format;
11409 var setCellClass = function(cal, cell){
11411 //Roo.log('set Cell Class');
11413 var t = d.getTime();
11417 cell.dateValue = t;
11419 cell.className += " fc-today";
11420 cell.className += " fc-state-highlight";
11421 cell.title = cal.todayText;
11424 // disable highlight in other month..
11425 //cell.className += " fc-state-highlight";
11430 cell.className = " fc-state-disabled";
11431 cell.title = cal.minText;
11435 cell.className = " fc-state-disabled";
11436 cell.title = cal.maxText;
11440 if(ddays.indexOf(d.getDay()) != -1){
11441 cell.title = ddaysText;
11442 cell.className = " fc-state-disabled";
11445 if(ddMatch && format){
11446 var fvalue = d.dateFormat(format);
11447 if(ddMatch.test(fvalue)){
11448 cell.title = ddText.replace("%0", fvalue);
11449 cell.className = " fc-state-disabled";
11453 if (!cell.initialClassName) {
11454 cell.initialClassName = cell.dom.className;
11457 cell.dom.className = cell.initialClassName + ' ' + cell.className;
11462 for(; i < startingPos; i++) {
11463 textEls[i].innerHTML = (++prevStart);
11464 d.setDate(d.getDate()+1);
11466 cells[i].className = "fc-past fc-other-month";
11467 setCellClass(this, cells[i]);
11472 for(; i < days; i++){
11473 intDay = i - startingPos + 1;
11474 textEls[i].innerHTML = (intDay);
11475 d.setDate(d.getDate()+1);
11477 cells[i].className = ''; // "x-date-active";
11478 setCellClass(this, cells[i]);
11482 for(; i < 42; i++) {
11483 textEls[i].innerHTML = (++extraDays);
11484 d.setDate(d.getDate()+1);
11486 cells[i].className = "fc-future fc-other-month";
11487 setCellClass(this, cells[i]);
11490 this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
11492 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
11494 this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
11495 this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
11497 if(totalRows != 6){
11498 this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
11499 this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
11502 this.fireEvent('monthchange', this, date);
11506 if(!this.internalRender){
11507 var main = this.el.dom.firstChild;
11508 var w = main.offsetWidth;
11509 this.el.setWidth(w + this.el.getBorderWidth("lr"));
11510 Roo.fly(main).setWidth(w);
11511 this.internalRender = true;
11512 // opera does not respect the auto grow header center column
11513 // then, after it gets a width opera refuses to recalculate
11514 // without a second pass
11515 if(Roo.isOpera && !this.secondPass){
11516 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
11517 this.secondPass = true;
11518 this.update.defer(10, this, [date]);
11525 findCell : function(dt) {
11526 dt = dt.clearTime().getTime();
11528 this.cells.each(function(c){
11529 //Roo.log("check " +c.dateValue + '?=' + dt);
11530 if(c.dateValue == dt){
11540 findCells : function(ev) {
11541 var s = ev.start.clone().clearTime().getTime();
11543 var e= ev.end.clone().clearTime().getTime();
11546 this.cells.each(function(c){
11547 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
11549 if(c.dateValue > e){
11552 if(c.dateValue < s){
11561 findBestRow: function(cells)
11565 for (var i =0 ; i < cells.length;i++) {
11566 ret = Math.max(cells[i].rows || 0,ret);
11573 addItem : function(ev)
11575 // look for vertical location slot in
11576 var cells = this.findCells(ev);
11578 ev.row = this.findBestRow(cells);
11580 // work out the location.
11584 for(var i =0; i < cells.length; i++) {
11592 if (crow.start.getY() == cells[i].getY()) {
11594 crow.end = cells[i];
11610 for (var i = 0; i < cells.length;i++) {
11611 cells[i].rows = Math.max(cells[i].rows || 0 , ev.row + 1 );
11615 this.calevents.push(ev);
11618 clearEvents: function() {
11620 if(!this.calevents){
11624 Roo.each(this.cells.elements, function(c){
11628 Roo.each(this.calevents, function(e) {
11629 Roo.each(e.els, function(el) {
11630 el.un('mouseenter' ,this.onEventEnter, this);
11631 el.un('mouseleave' ,this.onEventLeave, this);
11638 renderEvents: function()
11640 // first make sure there is enough space..
11642 this.cells.each(function(c) {
11644 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, c.rows * 20));
11647 for (var e = 0; e < this.calevents.length; e++) {
11648 var ev = this.calevents[e];
11649 var cells = ev.cells;
11650 var rows = ev.rows;
11652 for(var i =0; i < rows.length; i++) {
11655 // how many rows should it span..
11658 cls : 'roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable',
11659 style : 'position: absolute', // left: 387px; width: 121px; top: 359px;
11661 unselectable : "on",
11664 cls: 'fc-event-inner',
11668 // cls: 'fc-event-time',
11669 // html : cells.length > 1 ? '' : ev.time
11673 cls: 'fc-event-title',
11674 html : String.format('{0}', ev.title)
11681 cls: 'ui-resizable-handle ui-resizable-e',
11682 html : '  '
11688 cfg.cls += ' fc-event-start';
11690 if ((i+1) == rows.length) {
11691 cfg.cls += ' fc-event-end';
11694 var ctr = this.el.select('.fc-event-container',true).first();
11695 var cg = ctr.createChild(cfg);
11697 cg.on('mouseenter' ,this.onEventEnter, this, ev);
11698 cg.on('mouseleave' ,this.onEventLeave, this, ev);
11699 cg.on('click', this.onEventClick, this, ev);
11703 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
11704 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
11706 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
11707 cg.setWidth(ebox.right - sbox.x -2);
11715 onEventEnter: function (e, el,event,d) {
11716 this.fireEvent('evententer', this, el, event);
11719 onEventLeave: function (e, el,event,d) {
11720 this.fireEvent('eventleave', this, el, event);
11723 onEventClick: function (e, el,event,d) {
11724 this.fireEvent('eventclick', this, el, event);
11727 onMonthChange: function () {
11731 onLoad: function ()
11733 this.calevents = [];
11736 if(this.store.getCount() > 0){
11737 this.store.data.each(function(d){
11740 start: (typeof(d.data.start_dt) === 'string') ? new Date.parseDate(d.data.start_dt, 'Y-m-d H:i:s') : d.data.start_dt,
11741 end : (typeof(d.data.end_dt) === 'string') ? new Date.parseDate(d.data.end_dt, 'Y-m-d H:i:s') : d.data.end_dt,
11742 time : d.data.start_time,
11743 title : d.data.title,
11744 description : d.data.description,
11745 venue : d.data.venue
11750 this.renderEvents();
11753 this.maskEl.hide();
11757 onBeforeLoad: function()
11759 this.clearEvents();
11762 this.maskEl.show();
11776 * @class Roo.bootstrap.Popover
11777 * @extends Roo.bootstrap.Component
11778 * Bootstrap Popover class
11779 * @cfg {String} html contents of the popover (or false to use children..)
11780 * @cfg {String} title of popover (or false to hide)
11781 * @cfg {String} placement how it is placed
11782 * @cfg {String} trigger click || hover (or false to trigger manually)
11783 * @cfg {String} over what (parent or false to trigger manually.)
11786 * Create a new Popover
11787 * @param {Object} config The config object
11790 Roo.bootstrap.Popover = function(config){
11791 Roo.bootstrap.Popover.superclass.constructor.call(this, config);
11794 Roo.extend(Roo.bootstrap.Popover, Roo.bootstrap.Component, {
11796 title: 'Fill in a title',
11799 placement : 'right',
11800 trigger : 'hover', // hover
11804 can_build_overlaid : false,
11806 getChildContainer : function()
11808 return this.el.select('.popover-content',true).first();
11811 getAutoCreate : function(){
11812 Roo.log('make popover?');
11814 cls : 'popover roo-dynamic',
11815 style: 'display:block',
11821 cls : 'popover-inner',
11825 cls: 'popover-title',
11829 cls : 'popover-content',
11840 setTitle: function(str)
11842 this.el.select('.popover-title',true).first().dom.innerHTML = str;
11844 setContent: function(str)
11846 this.el.select('.popover-content',true).first().dom.innerHTML = str;
11848 // as it get's added to the bottom of the page.
11849 onRender : function(ct, position)
11851 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
11853 var cfg = Roo.apply({}, this.getAutoCreate());
11857 cfg.cls += ' ' + this.cls;
11860 cfg.style = this.style;
11862 Roo.log("adding to ")
11863 this.el = Roo.get(document.body).createChild(cfg, position);
11869 initEvents : function()
11871 this.el.select('.popover-title',true).setVisibilityMode(Roo.Element.DISPLAY);
11872 this.el.enableDisplayMode('block');
11874 if (this.over === false) {
11877 if (this.triggers === false) {
11880 var on_el = (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11881 var triggers = this.trigger ? this.trigger.split(' ') : [];
11882 Roo.each(triggers, function(trigger) {
11884 if (trigger == 'click') {
11885 on_el.on('click', this.toggle, this);
11886 } else if (trigger != 'manual') {
11887 var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
11888 var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
11890 on_el.on(eventIn ,this.enter, this);
11891 on_el.on(eventOut, this.leave, this);
11902 toggle : function () {
11903 this.hoverState == 'in' ? this.leave() : this.enter();
11906 enter : function () {
11909 clearTimeout(this.timeout);
11911 this.hoverState = 'in'
11913 if (!this.delay || !this.delay.show) {
11918 this.timeout = setTimeout(function () {
11919 if (_t.hoverState == 'in') {
11922 }, this.delay.show)
11924 leave : function() {
11925 clearTimeout(this.timeout);
11927 this.hoverState = 'out'
11929 if (!this.delay || !this.delay.hide) {
11934 this.timeout = setTimeout(function () {
11935 if (_t.hoverState == 'out') {
11938 }, this.delay.hide)
11941 show : function (on_el)
11944 on_el= (this.over == 'parent') ? this.parent().el : Roo.get(this.over);
11947 this.el.select('.popover-title',true).first().dom.innerHtml = this.title;
11948 if (this.html !== false) {
11949 this.el.select('.popover-content',true).first().dom.innerHtml = this.title;
11951 this.el.removeClass(['fade','top','bottom', 'left', 'right','in']);
11952 if (!this.title.length) {
11953 this.el.select('.popover-title',true).hide();
11956 var placement = typeof this.placement == 'function' ?
11957 this.placement.call(this, this.el, on_el) :
11960 var autoToken = /\s?auto?\s?/i;
11961 var autoPlace = autoToken.test(placement);
11963 placement = placement.replace(autoToken, '') || 'top';
11967 //this.el.setXY([0,0]);
11969 this.el.dom.style.display='block';
11970 this.el.addClass(placement);
11972 //this.el.appendTo(on_el);
11974 var p = this.getPosition();
11975 var box = this.el.getBox();
11980 var align = Roo.bootstrap.Popover.alignment[placement]
11981 this.el.alignTo(on_el, align[0],align[1]);
11982 //var arrow = this.el.select('.arrow',true).first();
11983 //arrow.set(align[2],
11985 this.el.addClass('in');
11986 this.hoverState = null;
11988 if (this.el.hasClass('fade')) {
11995 this.el.setXY([0,0]);
11996 this.el.removeClass('in');
12003 Roo.bootstrap.Popover.alignment = {
12004 'left' : ['r-l', [-10,0], 'right'],
12005 'right' : ['l-r', [10,0], 'left'],
12006 'bottom' : ['t-b', [0,10], 'top'],
12007 'top' : [ 'b-t', [0,-10], 'bottom']
12018 * @class Roo.bootstrap.Progress
12019 * @extends Roo.bootstrap.Component
12020 * Bootstrap Progress class
12021 * @cfg {Boolean} striped striped of the progress bar
12022 * @cfg {Boolean} active animated of the progress bar
12026 * Create a new Progress
12027 * @param {Object} config The config object
12030 Roo.bootstrap.Progress = function(config){
12031 Roo.bootstrap.Progress.superclass.constructor.call(this, config);
12034 Roo.extend(Roo.bootstrap.Progress, Roo.bootstrap.Component, {
12039 getAutoCreate : function(){
12047 cfg.cls += ' progress-striped';
12051 cfg.cls += ' active';
12070 * @class Roo.bootstrap.ProgressBar
12071 * @extends Roo.bootstrap.Component
12072 * Bootstrap ProgressBar class
12073 * @cfg {Number} aria_valuenow aria-value now
12074 * @cfg {Number} aria_valuemin aria-value min
12075 * @cfg {Number} aria_valuemax aria-value max
12076 * @cfg {String} label label for the progress bar
12077 * @cfg {String} panel (success | info | warning | danger )
12078 * @cfg {String} role role of the progress bar
12079 * @cfg {String} sr_only text
12083 * Create a new ProgressBar
12084 * @param {Object} config The config object
12087 Roo.bootstrap.ProgressBar = function(config){
12088 Roo.bootstrap.ProgressBar.superclass.constructor.call(this, config);
12091 Roo.extend(Roo.bootstrap.ProgressBar, Roo.bootstrap.Component, {
12095 aria_valuemax : 100,
12101 getAutoCreate : function()
12106 cls: 'progress-bar',
12107 style: 'width:' + Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%'
12119 cfg.role = this.role;
12122 if(this.aria_valuenow){
12123 cfg['aria-valuenow'] = this.aria_valuenow;
12126 if(this.aria_valuemin){
12127 cfg['aria-valuemin'] = this.aria_valuemin;
12130 if(this.aria_valuemax){
12131 cfg['aria-valuemax'] = this.aria_valuemax;
12134 if(this.label && !this.sr_only){
12135 cfg.html = this.label;
12139 cfg.cls += ' progress-bar-' + this.panel;
12145 update : function(aria_valuenow)
12147 this.aria_valuenow = aria_valuenow;
12149 this.el.setStyle('width', Math.ceil((this.aria_valuenow / this.aria_valuemax) * 100) + '%');
12164 * @class Roo.bootstrap.TabPanel
12165 * @extends Roo.bootstrap.Component
12166 * Bootstrap TabPanel class
12167 * @cfg {Boolean} active panel active
12168 * @cfg {String} html panel content
12169 * @cfg {String} tabId tab relate id
12170 * @cfg {String} navId The navbar which triggers show hide
12174 * Create a new TabPanel
12175 * @param {Object} config The config object
12178 Roo.bootstrap.TabPanel = function(config){
12179 Roo.bootstrap.TabPanel.superclass.constructor.call(this, config);
12183 * Fires when the active status changes
12184 * @param {Roo.bootstrap.TabPanel} this
12185 * @param {Boolean} state the new state
12192 Roo.extend(Roo.bootstrap.TabPanel, Roo.bootstrap.Component, {
12199 getAutoCreate : function(){
12203 html: this.html || ''
12207 cfg.cls += ' active';
12211 cfg.tabId = this.tabId;
12216 onRender : function(ct, position)
12218 // Roo.log("Call onRender: " + this.xtype);
12220 Roo.bootstrap.TabPanel.superclass.onRender.call(this, ct, position);
12222 if (this.navId && this.tabId) {
12223 var item = Roo.bootstrap.NavGroup.get(this.navId).getNavItem(this.tabId);
12225 Roo.log("could not find navID:" + this.navId + ", tabId: " + this.tabId);
12227 item.on('changed', function(e, item, state) {
12229 this.setActive(state);
12235 setActive: function(state)
12237 Roo.log("panel - set active " + this.tabId + "=" + state);
12239 this.active = state;
12241 this.el.removeClass('active');
12243 } else if (!this.el.hasClass('active')) {
12244 this.el.addClass('active');
12246 this.fireEvent('changed', this, state);
12263 * @class Roo.bootstrap.DateField
12264 * @extends Roo.bootstrap.Input
12265 * Bootstrap DateField class
12266 * @cfg {Number} weekStart default 0
12267 * @cfg {Number} weekStart default 0
12268 * @cfg {Number} viewMode default empty, (months|years)
12269 * @cfg {Number} minViewMode default empty, (months|years)
12270 * @cfg {Number} startDate default -Infinity
12271 * @cfg {Number} endDate default Infinity
12272 * @cfg {Boolean} todayHighlight default false
12273 * @cfg {Boolean} todayBtn default false
12274 * @cfg {Boolean} calendarWeeks default false
12275 * @cfg {Object} daysOfWeekDisabled default empty
12277 * @cfg {Boolean} keyboardNavigation default true
12278 * @cfg {String} language default en
12281 * Create a new DateField
12282 * @param {Object} config The config object
12285 Roo.bootstrap.DateField = function(config){
12286 Roo.bootstrap.DateField.superclass.constructor.call(this, config);
12290 * Fires when this field show.
12291 * @param {Roo.bootstrap.DateField} this
12292 * @param {Mixed} date The date value
12297 * Fires when this field hide.
12298 * @param {Roo.bootstrap.DateField} this
12299 * @param {Mixed} date The date value
12304 * Fires when select a date.
12305 * @param {Roo.bootstrap.DateField} this
12306 * @param {Mixed} date The date value
12312 Roo.extend(Roo.bootstrap.DateField, Roo.bootstrap.Input, {
12315 * @cfg {String} format
12316 * The default date format string which can be overriden for localization support. The format must be
12317 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
12321 * @cfg {String} altFormats
12322 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
12323 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
12325 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
12333 todayHighlight : false,
12339 keyboardNavigation: true,
12341 calendarWeeks: false,
12343 startDate: -Infinity,
12347 daysOfWeekDisabled: [],
12351 UTCDate: function()
12353 return new Date(Date.UTC.apply(Date, arguments));
12356 UTCToday: function()
12358 var today = new Date();
12359 return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
12362 getDate: function() {
12363 var d = this.getUTCDate();
12364 return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
12367 getUTCDate: function() {
12371 setDate: function(d) {
12372 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
12375 setUTCDate: function(d) {
12377 this.setValue(this.formatDate(this.date));
12380 onRender: function(ct, position)
12383 Roo.bootstrap.DateField.superclass.onRender.call(this, ct, position);
12385 this.language = this.language || 'en';
12386 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
12387 this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
12389 this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
12390 this.format = this.format || 'm/d/y';
12391 this.isInline = false;
12392 this.isInput = true;
12393 this.component = this.el.select('.add-on', true).first() || false;
12394 this.component = (this.component && this.component.length === 0) ? false : this.component;
12395 this.hasInput = this.component && this.inputEL().length;
12397 if (typeof(this.minViewMode === 'string')) {
12398 switch (this.minViewMode) {
12400 this.minViewMode = 1;
12403 this.minViewMode = 2;
12406 this.minViewMode = 0;
12411 if (typeof(this.viewMode === 'string')) {
12412 switch (this.viewMode) {
12425 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.DateField.template);
12427 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12429 this.picker().on('mousedown', this.onMousedown, this);
12430 this.picker().on('click', this.onClick, this);
12432 this.picker().addClass('datepicker-dropdown');
12434 this.startViewMode = this.viewMode;
12437 Roo.each(this.picker().select('tfoot th.today', true).elements, function(v){
12438 if(!this.calendarWeeks){
12443 v.dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today
12444 v.attr('colspan', function(i, val){
12445 return parseInt(val) + 1;
12450 this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
12452 this.setStartDate(this.startDate);
12453 this.setEndDate(this.endDate);
12455 this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
12462 if(this.isInline) {
12467 picker : function()
12469 return this.el.select('.datepicker', true).first();
12472 fillDow: function()
12474 var dowCnt = this.weekStart;
12483 if(this.calendarWeeks){
12491 while (dowCnt < this.weekStart + 7) {
12495 html: Roo.bootstrap.DateField.dates[this.language].daysMin[(dowCnt++)%7]
12499 this.picker().select('>.datepicker-days thead', true).first().createChild(dow);
12502 fillMonths: function()
12505 var months = this.picker().select('>.datepicker-months td', true).first();
12507 months.dom.innerHTML = '';
12513 html: Roo.bootstrap.DateField.dates[this.language].monthsShort[i++]
12516 months.createChild(month);
12521 update: function(){
12523 this.date = (typeof(this.date) === 'undefined') ? this.UTCToday() : (typeof(this.date) === 'string') ? this.parseDate(this.date) : this.date;
12525 if (this.date < this.startDate) {
12526 this.viewDate = new Date(this.startDate);
12527 } else if (this.date > this.endDate) {
12528 this.viewDate = new Date(this.endDate);
12530 this.viewDate = new Date(this.date);
12537 var d = new Date(this.viewDate),
12538 year = d.getUTCFullYear(),
12539 month = d.getUTCMonth(),
12540 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity,
12541 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity,
12542 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity,
12543 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity,
12544 currentDate = this.date && this.date.valueOf(),
12545 today = this.UTCToday();
12547 this.picker().select('>.datepicker-days thead th.switch', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].months[month]+' '+year;
12549 // this.picker().select('>tfoot th.today', true).first().dom.innerHTML = Roo.bootstrap.DateField.dates[this.language].today;
12551 // this.picker.select('>tfoot th.today').
12552 // .text(dates[this.language].today)
12553 // .toggle(this.todayBtn !== false);
12555 this.updateNavArrows();
12558 var prevMonth = this.UTCDate(year, month-1, 28,0,0,0,0),
12560 day = prevMonth.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
12562 prevMonth.setUTCDate(day);
12564 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7);
12566 var nextMonth = new Date(prevMonth);
12568 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
12570 nextMonth = nextMonth.valueOf();
12572 var fillMonths = false;
12574 this.picker().select('>.datepicker-days tbody',true).first().dom.innerHTML = '';
12576 while(prevMonth.valueOf() < nextMonth) {
12579 if (prevMonth.getUTCDay() === this.weekStart) {
12581 this.picker().select('>.datepicker-days tbody',true).first().createChild(fillMonths);
12589 if(this.calendarWeeks){
12590 // ISO 8601: First week contains first thursday.
12591 // ISO also states week starts on Monday, but we can be more abstract here.
12593 // Start of current week: based on weekstart/current date
12594 ws = new Date(+prevMonth + (this.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
12595 // Thursday of this week
12596 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
12597 // First Thursday of year, year from thursday
12598 yth = new Date(+(yth = this.UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5),
12599 // Calendar week: ms between thursdays, div ms per day, div 7 days
12600 calWeek = (th - yth) / 864e5 / 7 + 1;
12602 fillMonths.cn.push({
12610 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) {
12612 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) {
12615 if (this.todayHighlight &&
12616 prevMonth.getUTCFullYear() == today.getFullYear() &&
12617 prevMonth.getUTCMonth() == today.getMonth() &&
12618 prevMonth.getUTCDate() == today.getDate()) {
12619 clsName += ' today';
12622 if (currentDate && prevMonth.valueOf() === currentDate) {
12623 clsName += ' active';
12626 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate ||
12627 this.daysOfWeekDisabled.indexOf(prevMonth.getUTCDay()) !== -1) {
12628 clsName += ' disabled';
12631 fillMonths.cn.push({
12633 cls: 'day ' + clsName,
12634 html: prevMonth.getDate()
12637 prevMonth.setDate(prevMonth.getDate()+1);
12640 var currentYear = this.date && this.date.getUTCFullYear();
12641 var currentMonth = this.date && this.date.getUTCMonth();
12643 this.picker().select('>.datepicker-months th.switch',true).first().dom.innerHTML = year;
12645 Roo.each(this.picker().select('>.datepicker-months tbody span',true).elements, function(v,k){
12646 v.removeClass('active');
12648 if(currentYear === year && k === currentMonth){
12649 v.addClass('active');
12652 if (year < startYear || year > endYear || (year == startYear && k < startMonth) || (year == endYear && k > endMonth)) {
12653 v.addClass('disabled');
12659 year = parseInt(year/10, 10) * 10;
12661 this.picker().select('>.datepicker-years th.switch', true).first().dom.innerHTML = year + '-' + (year + 9);
12663 this.picker().select('>.datepicker-years tbody td',true).first().dom.innerHTML = '';
12666 for (var i = -1; i < 11; i++) {
12667 this.picker().select('>.datepicker-years tbody td',true).first().createChild({
12669 cls: 'year' + (i === -1 || i === 10 ? ' old' : '') + (currentYear === year ? ' active' : '') + (year < startYear || year > endYear ? ' disabled' : ''),
12677 showMode: function(dir) {
12679 this.viewMode = Math.max(this.minViewMode, Math.min(2, this.viewMode + dir));
12681 Roo.each(this.picker().select('>div',true).elements, function(v){
12682 v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
12685 this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
12690 if(this.isInline) return;
12692 this.picker().removeClass(['bottom', 'top']);
12694 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
12696 * place to the top of element!
12700 this.picker().addClass('top');
12701 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12706 this.picker().addClass('bottom');
12708 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
12711 parseDate : function(value){
12712 if(!value || value instanceof Date){
12715 var v = Date.parseDate(value, this.format);
12716 if (!v && this.useIso) {
12717 v = Date.parseDate(value, 'Y-m-d');
12719 if(!v && this.altFormats){
12720 if(!this.altFormatsArray){
12721 this.altFormatsArray = this.altFormats.split("|");
12723 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
12724 v = Date.parseDate(value, this.altFormatsArray[i]);
12730 formatDate : function(date, fmt){
12731 return (!date || !(date instanceof Date)) ?
12732 date : date.dateFormat(fmt || this.format);
12735 onFocus : function()
12737 Roo.bootstrap.DateField.superclass.onFocus.call(this);
12741 onBlur : function()
12743 Roo.bootstrap.DateField.superclass.onBlur.call(this);
12749 this.picker().show();
12753 this.fireEvent('show', this, this.date);
12758 if(this.isInline) return;
12759 this.picker().hide();
12760 this.viewMode = this.startViewMode;
12763 this.fireEvent('hide', this, this.date);
12767 onMousedown: function(e){
12768 e.stopPropagation();
12769 e.preventDefault();
12772 keyup: function(e){
12773 Roo.bootstrap.DateField.superclass.keyup.call(this);
12778 setValue: function(v){
12779 Roo.bootstrap.DateField.superclass.setValue.call(this, v);
12781 this.fireEvent('select', this, this.date);
12785 fireKey: function(e){
12786 if (!this.picker().isVisible()){
12787 if (e.keyCode == 27) // allow escape to hide and re-show picker
12791 var dateChanged = false,
12793 newDate, newViewDate;
12797 e.preventDefault();
12801 if (!this.keyboardNavigation) break;
12802 dir = e.keyCode == 37 ? -1 : 1;
12805 newDate = this.moveYear(this.date, dir);
12806 newViewDate = this.moveYear(this.viewDate, dir);
12807 } else if (e.shiftKey){
12808 newDate = this.moveMonth(this.date, dir);
12809 newViewDate = this.moveMonth(this.viewDate, dir);
12811 newDate = new Date(this.date);
12812 newDate.setUTCDate(this.date.getUTCDate() + dir);
12813 newViewDate = new Date(this.viewDate);
12814 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
12816 if (this.dateWithinRange(newDate)){
12817 this.date = newDate;
12818 this.viewDate = newViewDate;
12819 this.setValue(this.formatDate(this.date));
12821 e.preventDefault();
12822 dateChanged = true;
12827 if (!this.keyboardNavigation) break;
12828 dir = e.keyCode == 38 ? -1 : 1;
12830 newDate = this.moveYear(this.date, dir);
12831 newViewDate = this.moveYear(this.viewDate, dir);
12832 } else if (e.shiftKey){
12833 newDate = this.moveMonth(this.date, dir);
12834 newViewDate = this.moveMonth(this.viewDate, dir);
12836 newDate = new Date(this.date);
12837 newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
12838 newViewDate = new Date(this.viewDate);
12839 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
12841 if (this.dateWithinRange(newDate)){
12842 this.date = newDate;
12843 this.viewDate = newViewDate;
12844 this.setValue(this.formatDate(this.date));
12846 e.preventDefault();
12847 dateChanged = true;
12851 this.setValue(this.formatDate(this.date));
12853 e.preventDefault();
12856 this.setValue(this.formatDate(this.date));
12863 onClick: function(e) {
12864 e.stopPropagation();
12865 e.preventDefault();
12867 var target = e.getTarget();
12869 if(target.nodeName.toLowerCase() === 'i'){
12870 target = Roo.get(target).dom.parentNode;
12873 var nodeName = target.nodeName;
12874 var className = target.className;
12875 var html = target.innerHTML;
12877 switch(nodeName.toLowerCase()) {
12879 switch(className) {
12885 var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
12886 switch(this.viewMode){
12888 this.viewDate = this.moveMonth(this.viewDate, dir);
12892 this.viewDate = this.moveYear(this.viewDate, dir);
12898 var date = new Date();
12899 this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
12901 this.setValue(this.formatDate(this.date));
12907 if (className.indexOf('disabled') === -1) {
12908 this.viewDate.setUTCDate(1);
12909 if (className.indexOf('month') !== -1) {
12910 this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
12912 var year = parseInt(html, 10) || 0;
12913 this.viewDate.setUTCFullYear(year);
12922 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
12923 var day = parseInt(html, 10) || 1;
12924 var year = this.viewDate.getUTCFullYear(),
12925 month = this.viewDate.getUTCMonth();
12927 if (className.indexOf('old') !== -1) {
12934 } else if (className.indexOf('new') !== -1) {
12942 this.date = this.UTCDate(year, month, day,0,0,0,0);
12943 this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
12945 this.setValue(this.formatDate(this.date));
12952 setStartDate: function(startDate){
12953 this.startDate = startDate || -Infinity;
12954 if (this.startDate !== -Infinity) {
12955 this.startDate = this.parseDate(this.startDate);
12958 this.updateNavArrows();
12961 setEndDate: function(endDate){
12962 this.endDate = endDate || Infinity;
12963 if (this.endDate !== Infinity) {
12964 this.endDate = this.parseDate(this.endDate);
12967 this.updateNavArrows();
12970 setDaysOfWeekDisabled: function(daysOfWeekDisabled){
12971 this.daysOfWeekDisabled = daysOfWeekDisabled || [];
12972 if (typeof(this.daysOfWeekDisabled) !== 'object') {
12973 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
12975 this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
12976 return parseInt(d, 10);
12979 this.updateNavArrows();
12982 updateNavArrows: function() {
12983 var d = new Date(this.viewDate),
12984 year = d.getUTCFullYear(),
12985 month = d.getUTCMonth();
12987 Roo.each(this.picker().select('.prev', true).elements, function(v){
12989 switch (this.viewMode) {
12992 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
12998 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
13005 Roo.each(this.picker().select('.next', true).elements, function(v){
13007 switch (this.viewMode) {
13010 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
13016 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
13024 moveMonth: function(date, dir){
13025 if (!dir) return date;
13026 var new_date = new Date(date.valueOf()),
13027 day = new_date.getUTCDate(),
13028 month = new_date.getUTCMonth(),
13029 mag = Math.abs(dir),
13031 dir = dir > 0 ? 1 : -1;
13034 // If going back one month, make sure month is not current month
13035 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
13037 return new_date.getUTCMonth() == month;
13039 // If going forward one month, make sure month is as expected
13040 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
13042 return new_date.getUTCMonth() != new_month;
13044 new_month = month + dir;
13045 new_date.setUTCMonth(new_month);
13046 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
13047 if (new_month < 0 || new_month > 11)
13048 new_month = (new_month + 12) % 12;
13050 // For magnitudes >1, move one month at a time...
13051 for (var i=0; i<mag; i++)
13052 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
13053 new_date = this.moveMonth(new_date, dir);
13054 // ...then reset the day, keeping it in the new month
13055 new_month = new_date.getUTCMonth();
13056 new_date.setUTCDate(day);
13058 return new_month != new_date.getUTCMonth();
13061 // Common date-resetting loop -- if date is beyond end of month, make it
13064 new_date.setUTCDate(--day);
13065 new_date.setUTCMonth(new_month);
13070 moveYear: function(date, dir){
13071 return this.moveMonth(date, dir*12);
13074 dateWithinRange: function(date){
13075 return date >= this.startDate && date <= this.endDate;
13079 remove: function() {
13080 this.picker().remove();
13085 Roo.apply(Roo.bootstrap.DateField, {
13096 html: '<i class="icon-arrow-left"/>'
13106 html: '<i class="icon-arrow-right"/>'
13148 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"],
13149 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"],
13150 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"],
13151 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"],
13152 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
13165 navFnc: 'FullYear',
13170 navFnc: 'FullYear',
13175 Roo.apply(Roo.bootstrap.DateField, {
13179 cls: 'datepicker dropdown-menu',
13183 cls: 'datepicker-days',
13187 cls: 'table-condensed',
13189 Roo.bootstrap.DateField.head,
13193 Roo.bootstrap.DateField.footer
13200 cls: 'datepicker-months',
13204 cls: 'table-condensed',
13206 Roo.bootstrap.DateField.head,
13207 Roo.bootstrap.DateField.content,
13208 Roo.bootstrap.DateField.footer
13215 cls: 'datepicker-years',
13219 cls: 'table-condensed',
13221 Roo.bootstrap.DateField.head,
13222 Roo.bootstrap.DateField.content,
13223 Roo.bootstrap.DateField.footer
13242 * @class Roo.bootstrap.TimeField
13243 * @extends Roo.bootstrap.Input
13244 * Bootstrap DateField class
13248 * Create a new TimeField
13249 * @param {Object} config The config object
13252 Roo.bootstrap.TimeField = function(config){
13253 Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
13257 * Fires when this field show.
13258 * @param {Roo.bootstrap.DateField} this
13259 * @param {Mixed} date The date value
13264 * Fires when this field hide.
13265 * @param {Roo.bootstrap.DateField} this
13266 * @param {Mixed} date The date value
13271 * Fires when select a date.
13272 * @param {Roo.bootstrap.DateField} this
13273 * @param {Mixed} date The date value
13279 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input, {
13282 * @cfg {String} format
13283 * The default time format string which can be overriden for localization support. The format must be
13284 * valid according to {@link Date#parseDate} (defaults to 'H:i').
13288 onRender: function(ct, position)
13291 Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
13293 this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
13295 this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
13297 this.pop = this.picker().select('>.datepicker-time',true).first();
13298 this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block'
13300 this.picker().on('mousedown', this.onMousedown, this);
13301 this.picker().on('click', this.onClick, this);
13303 this.picker().addClass('datepicker-dropdown');
13308 this.pop.select('span.hours-up', true).first().on('click', this.onIncrementHours, this);
13309 this.pop.select('span.hours-down', true).first().on('click', this.onDecrementHours, this);
13310 this.pop.select('span.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
13311 this.pop.select('span.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
13312 this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
13313 this.pop.select('button.ok', true).first().on('click', this.setTime, this);
13317 fireKey: function(e){
13318 if (!this.picker().isVisible()){
13319 if (e.keyCode == 27) // allow escape to hide and re-show picker
13324 e.preventDefault();
13332 this.onTogglePeriod();
13335 this.onIncrementMinutes();
13338 this.onDecrementMinutes();
13347 onClick: function(e) {
13348 e.stopPropagation();
13349 e.preventDefault();
13352 picker : function()
13354 return this.el.select('.datepicker', true).first();
13357 fillTime: function()
13359 var time = this.pop.select('tbody', true).first();
13361 time.dom.innerHTML = '';
13376 cls: 'hours-up glyphicon glyphicon-chevron-up'
13396 cls: 'minutes-up glyphicon glyphicon-chevron-up'
13417 cls: 'timepicker-hour',
13432 cls: 'timepicker-minute',
13447 cls: 'btn btn-primary period',
13469 cls: 'hours-down glyphicon glyphicon-chevron-down'
13489 cls: 'minutes-down glyphicon glyphicon-chevron-down'
13507 this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
13514 var hours = this.time.getHours();
13515 var minutes = this.time.getMinutes();
13528 hours = hours - 12;
13532 hours = '0' + hours;
13536 minutes = '0' + minutes;
13539 this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
13540 this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
13541 this.pop.select('button', true).first().dom.innerHTML = period;
13547 this.picker().removeClass(['bottom', 'top']);
13549 if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
13551 * place to the top of element!
13555 this.picker().addClass('top');
13556 this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13561 this.picker().addClass('bottom');
13563 this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
13566 onFocus : function()
13568 Roo.bootstrap.TimeField.superclass.onFocus.call(this);
13572 onBlur : function()
13574 Roo.bootstrap.TimeField.superclass.onBlur.call(this);
13580 this.picker().show();
13585 this.fireEvent('show', this, this.date);
13590 this.picker().hide();
13593 this.fireEvent('hide', this, this.date);
13596 setTime : function()
13599 this.setValue(this.time.format(this.format));
13601 this.fireEvent('select', this, this.date);
13606 onMousedown: function(e){
13607 e.stopPropagation();
13608 e.preventDefault();
13611 onIncrementHours: function()
13613 Roo.log('onIncrementHours');
13614 this.time = this.time.add(Date.HOUR, 1);
13619 onDecrementHours: function()
13621 Roo.log('onDecrementHours');
13622 this.time = this.time.add(Date.HOUR, -1);
13626 onIncrementMinutes: function()
13628 Roo.log('onIncrementMinutes');
13629 this.time = this.time.add(Date.MINUTE, 1);
13633 onDecrementMinutes: function()
13635 Roo.log('onDecrementMinutes');
13636 this.time = this.time.add(Date.MINUTE, -1);
13640 onTogglePeriod: function()
13642 Roo.log('onTogglePeriod');
13643 this.time = this.time.add(Date.HOUR, 12);
13650 Roo.apply(Roo.bootstrap.TimeField, {
13680 cls: 'btn btn-info ok',
13692 Roo.apply(Roo.bootstrap.TimeField, {
13696 cls: 'datepicker dropdown-menu',
13700 cls: 'datepicker-time',
13704 cls: 'table-condensed',
13706 Roo.bootstrap.TimeField.content,
13707 Roo.bootstrap.TimeField.footer
13726 * @class Roo.bootstrap.CheckBox
13727 * @extends Roo.bootstrap.Input
13728 * Bootstrap CheckBox class
13730 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
13731 * @cfg {String} inputValue The value that should go into the generated input element's value when checked.
13732 * @cfg {String} boxLabel The text that appears beside the checkbox
13733 * @cfg {Boolean} checked initnal the element
13736 * Create a new CheckBox
13737 * @param {Object} config The config object
13740 Roo.bootstrap.CheckBox = function(config){
13741 Roo.bootstrap.CheckBox.superclass.constructor.call(this, config);
13746 * Fires when the element is checked or unchecked.
13747 * @param {Roo.bootstrap.CheckBox} this This input
13748 * @param {Boolean} checked The new checked value
13754 Roo.extend(Roo.bootstrap.CheckBox, Roo.bootstrap.Input, {
13756 inputType: 'checkbox',
13762 getAutoCreate : function()
13764 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13770 cfg.cls = 'form-group' //input-group
13775 type : this.inputType,
13776 value : (!this.checked) ? this.valueOff : this.inputValue,
13778 placeholder : this.placeholder || ''
13782 if (this.disabled) {
13783 input.disabled=true;
13787 input.checked = this.checked;
13791 input.name = this.name;
13795 input.cls += ' input-' + this.size;
13799 ['xs','sm','md','lg'].map(function(size){
13800 if (settings[size]) {
13801 cfg.cls += ' col-' + size + '-' + settings[size];
13805 var inputblock = input;
13807 if (this.before || this.after) {
13810 cls : 'input-group',
13814 inputblock.cn.push({
13816 cls : 'input-group-addon',
13820 inputblock.cn.push(input);
13822 inputblock.cn.push({
13824 cls : 'input-group-addon',
13831 if (align ==='left' && this.fieldLabel.length) {
13832 Roo.log("left and has label");
13838 cls : 'control-label col-md-' + this.labelWidth,
13839 html : this.fieldLabel
13843 cls : "col-md-" + (12 - this.labelWidth),
13850 } else if ( this.fieldLabel.length) {
13855 tag: this.boxLabel ? 'span' : 'label',
13857 cls: 'control-label box-input-label',
13858 //cls : 'input-group-addon',
13859 html : this.fieldLabel
13869 Roo.log(" no label && no align");
13884 html: this.boxLabel
13893 * return the real input element.
13895 inputEl: function ()
13897 return this.el.select('input.form-box',true).first();
13902 return this.el.select('label.control-label',true).first();
13905 initEvents : function()
13907 // Roo.bootstrap.CheckBox.superclass.initEvents.call(this);
13909 this.inputEl().on('click', this.onClick, this);
13913 onClick : function()
13915 this.setChecked(!this.checked);
13918 setChecked : function(state,suppressEvent)
13920 this.checked = state;
13922 this.inputEl().dom.checked = state;
13924 if(suppressEvent !== true){
13925 this.fireEvent('check', this, state);
13928 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
13932 setValue : function(v,suppressEvent)
13934 this.setChecked(((typeof(v) == 'undefined') ? this.checked : (String(v) === String(this.inputValue))), suppressEvent);
13948 * @class Roo.bootstrap.Radio
13949 * @extends Roo.bootstrap.CheckBox
13950 * Bootstrap Radio class
13953 * Create a new Radio
13954 * @param {Object} config The config object
13957 Roo.bootstrap.Radio = function(config){
13958 Roo.bootstrap.Radio.superclass.constructor.call(this, config);
13962 Roo.extend(Roo.bootstrap.Radio, Roo.bootstrap.CheckBox, {
13964 inputType: 'radio',
13968 getAutoCreate : function()
13970 var align = (!this.labelAlign) ? this.parentLabelAlign() : this.labelAlign;
13976 cfg.cls = 'form-group' //input-group
13981 type : this.inputType,
13982 value : (!this.checked) ? this.valueOff : this.inputValue,
13984 placeholder : this.placeholder || ''
13988 if (this.disabled) {
13989 input.disabled=true;
13993 input.checked = this.checked;
13997 input.name = this.name;
14001 input.cls += ' input-' + this.size;
14005 ['xs','sm','md','lg'].map(function(size){
14006 if (settings[size]) {
14007 cfg.cls += ' col-' + size + '-' + settings[size];
14011 var inputblock = input;
14013 if (this.before || this.after) {
14016 cls : 'input-group',
14020 inputblock.cn.push({
14022 cls : 'input-group-addon',
14026 inputblock.cn.push(input);
14028 inputblock.cn.push({
14030 cls : 'input-group-addon',
14037 if (align ==='left' && this.fieldLabel.length) {
14038 Roo.log("left and has label");
14044 cls : 'control-label col-md-' + this.labelWidth,
14045 html : this.fieldLabel
14049 cls : "col-md-" + (12 - this.labelWidth),
14056 } else if ( this.fieldLabel.length) {
14063 cls: 'control-label box-input-label',
14064 //cls : 'input-group-addon',
14065 html : this.fieldLabel
14075 Roo.log(" no label && no align");
14090 html: this.boxLabel
14098 onClick : function()
14100 this.setChecked(true);
14103 setChecked : function(state,suppressEvent)
14106 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14107 v.dom.checked = false;
14111 this.checked = state;
14112 this.inputEl().dom.checked = state;
14114 if(suppressEvent !== true){
14115 this.fireEvent('check', this, state);
14118 this.inputEl().dom.value = state ? this.inputValue : this.valueOff;
14122 getGroupValue : function()
14125 Roo.each(this.inputEl().up('form').select('input[name='+this.inputEl().dom.name+']', true).elements, function(v){
14126 if(v.dom.checked == true){
14127 value = v.dom.value;
14135 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
14136 * @return {Mixed} value The field value
14138 getValue : function(){
14139 return this.getGroupValue();
14145 //<script type="text/javascript">
14148 * Based Ext JS Library 1.1.1
14149 * Copyright(c) 2006-2007, Ext JS, LLC.
14155 * @class Roo.HtmlEditorCore
14156 * @extends Roo.Component
14157 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
14159 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
14162 Roo.HtmlEditorCore = function(config){
14165 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
14168 * @event initialize
14169 * Fires when the editor is fully initialized (including the iframe)
14170 * @param {Roo.HtmlEditorCore} this
14175 * Fires when the editor is first receives the focus. Any insertion must wait
14176 * until after this event.
14177 * @param {Roo.HtmlEditorCore} this
14181 * @event beforesync
14182 * Fires before the textarea is updated with content from the editor iframe. Return false
14183 * to cancel the sync.
14184 * @param {Roo.HtmlEditorCore} this
14185 * @param {String} html
14189 * @event beforepush
14190 * Fires before the iframe editor is updated with content from the textarea. Return false
14191 * to cancel the push.
14192 * @param {Roo.HtmlEditorCore} this
14193 * @param {String} html
14198 * Fires when the textarea is updated with content from the editor iframe.
14199 * @param {Roo.HtmlEditorCore} this
14200 * @param {String} html
14205 * Fires when the iframe editor is updated with content from the textarea.
14206 * @param {Roo.HtmlEditorCore} this
14207 * @param {String} html
14212 * @event editorevent
14213 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
14214 * @param {Roo.HtmlEditorCore} this
14222 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
14226 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
14232 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
14237 * @cfg {Number} height (in pixels)
14241 * @cfg {Number} width (in pixels)
14246 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
14249 stylesheets: false,
14254 // private properties
14255 validationEvent : false,
14257 initialized : false,
14259 sourceEditMode : false,
14260 onFocus : Roo.emptyFn,
14262 hideMode:'offsets',
14270 * Protected method that will not generally be called directly. It
14271 * is called when the editor initializes the iframe with HTML contents. Override this method if you
14272 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
14274 getDocMarkup : function(){
14277 Roo.log(this.stylesheets);
14279 // inherit styels from page...??
14280 if (this.stylesheets === false) {
14282 Roo.get(document.head).select('style').each(function(node) {
14283 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14286 Roo.get(document.head).select('link').each(function(node) {
14287 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
14290 } else if (!this.stylesheets.length) {
14292 st = '<style type="text/css">' +
14293 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14296 Roo.each(this.stylesheets, function(s) {
14297 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
14302 st += '<style type="text/css">' +
14303 'IMG { cursor: pointer } ' +
14307 return '<html><head>' + st +
14308 //<style type="text/css">' +
14309 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
14311 ' </head><body class="roo-htmleditor-body"></body></html>';
14315 onRender : function(ct, position)
14318 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
14319 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
14322 this.el.dom.style.border = '0 none';
14323 this.el.dom.setAttribute('tabIndex', -1);
14324 this.el.addClass('x-hidden hide');
14328 if(Roo.isIE){ // fix IE 1px bogus margin
14329 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
14333 this.frameId = Roo.id();
14337 var iframe = this.owner.wrap.createChild({
14339 cls: 'form-control', // bootstrap..
14341 name: this.frameId,
14342 frameBorder : 'no',
14343 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
14348 this.iframe = iframe.dom;
14350 this.assignDocWin();
14352 this.doc.designMode = 'on';
14355 this.doc.write(this.getDocMarkup());
14359 var task = { // must defer to wait for browser to be ready
14361 //console.log("run task?" + this.doc.readyState);
14362 this.assignDocWin();
14363 if(this.doc.body || this.doc.readyState == 'complete'){
14365 this.doc.designMode="on";
14369 Roo.TaskMgr.stop(task);
14370 this.initEditor.defer(10, this);
14377 Roo.TaskMgr.start(task);
14384 onResize : function(w, h)
14386 Roo.log('resize: ' +w + ',' + h );
14387 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
14391 if(typeof w == 'number'){
14393 this.iframe.style.width = w + 'px';
14395 if(typeof h == 'number'){
14397 this.iframe.style.height = h + 'px';
14399 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
14406 * Toggles the editor between standard and source edit mode.
14407 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
14409 toggleSourceEdit : function(sourceEditMode){
14411 this.sourceEditMode = sourceEditMode === true;
14413 if(this.sourceEditMode){
14415 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
14418 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
14419 //this.iframe.className = '';
14422 //this.setSize(this.owner.wrap.getSize());
14423 //this.fireEvent('editmodechange', this, this.sourceEditMode);
14430 * Protected method that will not generally be called directly. If you need/want
14431 * custom HTML cleanup, this is the method you should override.
14432 * @param {String} html The HTML to be cleaned
14433 * return {String} The cleaned HTML
14435 cleanHtml : function(html){
14436 html = String(html);
14437 if(html.length > 5){
14438 if(Roo.isSafari){ // strip safari nonsense
14439 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
14442 if(html == ' '){
14449 * HTML Editor -> Textarea
14450 * Protected method that will not generally be called directly. Syncs the contents
14451 * of the editor iframe with the textarea.
14453 syncValue : function(){
14454 if(this.initialized){
14455 var bd = (this.doc.body || this.doc.documentElement);
14456 //this.cleanUpPaste(); -- this is done else where and causes havoc..
14457 var html = bd.innerHTML;
14459 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
14460 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
14462 html = '<div style="'+m[0]+'">' + html + '</div>';
14465 html = this.cleanHtml(html);
14466 // fix up the special chars.. normaly like back quotes in word...
14467 // however we do not want to do this with chinese..
14468 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
14469 var cc = b.charCodeAt();
14471 (cc >= 0x4E00 && cc < 0xA000 ) ||
14472 (cc >= 0x3400 && cc < 0x4E00 ) ||
14473 (cc >= 0xf900 && cc < 0xfb00 )
14479 if(this.owner.fireEvent('beforesync', this, html) !== false){
14480 this.el.dom.value = html;
14481 this.owner.fireEvent('sync', this, html);
14487 * Protected method that will not generally be called directly. Pushes the value of the textarea
14488 * into the iframe editor.
14490 pushValue : function(){
14491 if(this.initialized){
14492 var v = this.el.dom.value.trim();
14494 // if(v.length < 1){
14498 if(this.owner.fireEvent('beforepush', this, v) !== false){
14499 var d = (this.doc.body || this.doc.documentElement);
14501 this.cleanUpPaste();
14502 this.el.dom.value = d.innerHTML;
14503 this.owner.fireEvent('push', this, v);
14509 deferFocus : function(){
14510 this.focus.defer(10, this);
14514 focus : function(){
14515 if(this.win && !this.sourceEditMode){
14522 assignDocWin: function()
14524 var iframe = this.iframe;
14527 this.doc = iframe.contentWindow.document;
14528 this.win = iframe.contentWindow;
14530 if (!Roo.get(this.frameId)) {
14533 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
14534 this.win = Roo.get(this.frameId).dom.contentWindow;
14539 initEditor : function(){
14540 //console.log("INIT EDITOR");
14541 this.assignDocWin();
14545 this.doc.designMode="on";
14547 this.doc.write(this.getDocMarkup());
14550 var dbody = (this.doc.body || this.doc.documentElement);
14551 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
14552 // this copies styles from the containing element into thsi one..
14553 // not sure why we need all of this..
14554 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
14555 ss['background-attachment'] = 'fixed'; // w3c
14556 dbody.bgProperties = 'fixed'; // ie
14557 Roo.DomHelper.applyStyles(dbody, ss);
14558 Roo.EventManager.on(this.doc, {
14559 //'mousedown': this.onEditorEvent,
14560 'mouseup': this.onEditorEvent,
14561 'dblclick': this.onEditorEvent,
14562 'click': this.onEditorEvent,
14563 'keyup': this.onEditorEvent,
14568 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
14570 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
14571 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
14573 this.initialized = true;
14575 this.owner.fireEvent('initialize', this);
14580 onDestroy : function(){
14586 //for (var i =0; i < this.toolbars.length;i++) {
14587 // // fixme - ask toolbars for heights?
14588 // this.toolbars[i].onDestroy();
14591 //this.wrap.dom.innerHTML = '';
14592 //this.wrap.remove();
14597 onFirstFocus : function(){
14599 this.assignDocWin();
14602 this.activated = true;
14605 if(Roo.isGecko){ // prevent silly gecko errors
14607 var s = this.win.getSelection();
14608 if(!s.focusNode || s.focusNode.nodeType != 3){
14609 var r = s.getRangeAt(0);
14610 r.selectNodeContents((this.doc.body || this.doc.documentElement));
14615 this.execCmd('useCSS', true);
14616 this.execCmd('styleWithCSS', false);
14619 this.owner.fireEvent('activate', this);
14623 adjustFont: function(btn){
14624 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
14625 //if(Roo.isSafari){ // safari
14628 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
14629 if(Roo.isSafari){ // safari
14630 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
14631 v = (v < 10) ? 10 : v;
14632 v = (v > 48) ? 48 : v;
14633 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
14638 v = Math.max(1, v+adjust);
14640 this.execCmd('FontSize', v );
14643 onEditorEvent : function(e){
14644 this.owner.fireEvent('editorevent', this, e);
14645 // this.updateToolbar();
14646 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
14649 insertTag : function(tg)
14651 // could be a bit smarter... -> wrap the current selected tRoo..
14652 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
14654 range = this.createRange(this.getSelection());
14655 var wrappingNode = this.doc.createElement(tg.toLowerCase());
14656 wrappingNode.appendChild(range.extractContents());
14657 range.insertNode(wrappingNode);
14664 this.execCmd("formatblock", tg);
14668 insertText : function(txt)
14672 var range = this.createRange();
14673 range.deleteContents();
14674 //alert(Sender.getAttribute('label'));
14676 range.insertNode(this.doc.createTextNode(txt));
14682 * Executes a Midas editor command on the editor document and performs necessary focus and
14683 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
14684 * @param {String} cmd The Midas command
14685 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14687 relayCmd : function(cmd, value){
14689 this.execCmd(cmd, value);
14690 this.owner.fireEvent('editorevent', this);
14691 //this.updateToolbar();
14692 this.owner.deferFocus();
14696 * Executes a Midas editor command directly on the editor document.
14697 * For visual commands, you should use {@link #relayCmd} instead.
14698 * <b>This should only be called after the editor is initialized.</b>
14699 * @param {String} cmd The Midas command
14700 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
14702 execCmd : function(cmd, value){
14703 this.doc.execCommand(cmd, false, value === undefined ? null : value);
14710 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
14712 * @param {String} text | dom node..
14714 insertAtCursor : function(text)
14719 if(!this.activated){
14725 var r = this.doc.selection.createRange();
14736 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
14740 // from jquery ui (MIT licenced)
14742 var win = this.win;
14744 if (win.getSelection && win.getSelection().getRangeAt) {
14745 range = win.getSelection().getRangeAt(0);
14746 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
14747 range.insertNode(node);
14748 } else if (win.document.selection && win.document.selection.createRange) {
14749 // no firefox support
14750 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14751 win.document.selection.createRange().pasteHTML(txt);
14753 // no firefox support
14754 var txt = typeof(text) == 'string' ? text : text.outerHTML;
14755 this.execCmd('InsertHTML', txt);
14764 mozKeyPress : function(e){
14766 var c = e.getCharCode(), cmd;
14769 c = String.fromCharCode(c).toLowerCase();
14783 this.cleanUpPaste.defer(100, this);
14791 e.preventDefault();
14799 fixKeys : function(){ // load time branching for fastest keydown performance
14801 return function(e){
14802 var k = e.getKey(), r;
14805 r = this.doc.selection.createRange();
14808 r.pasteHTML('    ');
14815 r = this.doc.selection.createRange();
14817 var target = r.parentElement();
14818 if(!target || target.tagName.toLowerCase() != 'li'){
14820 r.pasteHTML('<br />');
14826 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14827 this.cleanUpPaste.defer(100, this);
14833 }else if(Roo.isOpera){
14834 return function(e){
14835 var k = e.getKey();
14839 this.execCmd('InsertHTML','    ');
14842 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14843 this.cleanUpPaste.defer(100, this);
14848 }else if(Roo.isSafari){
14849 return function(e){
14850 var k = e.getKey();
14854 this.execCmd('InsertText','\t');
14858 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
14859 this.cleanUpPaste.defer(100, this);
14867 getAllAncestors: function()
14869 var p = this.getSelectedNode();
14872 a.push(p); // push blank onto stack..
14873 p = this.getParentElement();
14877 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
14881 a.push(this.doc.body);
14885 lastSelNode : false,
14888 getSelection : function()
14890 this.assignDocWin();
14891 return Roo.isIE ? this.doc.selection : this.win.getSelection();
14894 getSelectedNode: function()
14896 // this may only work on Gecko!!!
14898 // should we cache this!!!!
14903 var range = this.createRange(this.getSelection()).cloneRange();
14906 var parent = range.parentElement();
14908 var testRange = range.duplicate();
14909 testRange.moveToElementText(parent);
14910 if (testRange.inRange(range)) {
14913 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
14916 parent = parent.parentElement;
14921 // is ancestor a text element.
14922 var ac = range.commonAncestorContainer;
14923 if (ac.nodeType == 3) {
14924 ac = ac.parentNode;
14927 var ar = ac.childNodes;
14930 var other_nodes = [];
14931 var has_other_nodes = false;
14932 for (var i=0;i<ar.length;i++) {
14933 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
14936 // fullly contained node.
14938 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
14943 // probably selected..
14944 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
14945 other_nodes.push(ar[i]);
14949 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
14954 has_other_nodes = true;
14956 if (!nodes.length && other_nodes.length) {
14957 nodes= other_nodes;
14959 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
14965 createRange: function(sel)
14967 // this has strange effects when using with
14968 // top toolbar - not sure if it's a great idea.
14969 //this.editor.contentWindow.focus();
14970 if (typeof sel != "undefined") {
14972 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
14974 return this.doc.createRange();
14977 return this.doc.createRange();
14980 getParentElement: function()
14983 this.assignDocWin();
14984 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
14986 var range = this.createRange(sel);
14989 var p = range.commonAncestorContainer;
14990 while (p.nodeType == 3) { // text node
15001 * Range intersection.. the hard stuff...
15005 * [ -- selected range --- ]
15009 * if end is before start or hits it. fail.
15010 * if start is after end or hits it fail.
15012 * if either hits (but other is outside. - then it's not
15018 // @see http://www.thismuchiknow.co.uk/?p=64.
15019 rangeIntersectsNode : function(range, node)
15021 var nodeRange = node.ownerDocument.createRange();
15023 nodeRange.selectNode(node);
15025 nodeRange.selectNodeContents(node);
15028 var rangeStartRange = range.cloneRange();
15029 rangeStartRange.collapse(true);
15031 var rangeEndRange = range.cloneRange();
15032 rangeEndRange.collapse(false);
15034 var nodeStartRange = nodeRange.cloneRange();
15035 nodeStartRange.collapse(true);
15037 var nodeEndRange = nodeRange.cloneRange();
15038 nodeEndRange.collapse(false);
15040 return rangeStartRange.compareBoundaryPoints(
15041 Range.START_TO_START, nodeEndRange) == -1 &&
15042 rangeEndRange.compareBoundaryPoints(
15043 Range.START_TO_START, nodeStartRange) == 1;
15047 rangeCompareNode : function(range, node)
15049 var nodeRange = node.ownerDocument.createRange();
15051 nodeRange.selectNode(node);
15053 nodeRange.selectNodeContents(node);
15057 range.collapse(true);
15059 nodeRange.collapse(true);
15061 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
15062 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
15064 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
15066 var nodeIsBefore = ss == 1;
15067 var nodeIsAfter = ee == -1;
15069 if (nodeIsBefore && nodeIsAfter)
15071 if (!nodeIsBefore && nodeIsAfter)
15072 return 1; //right trailed.
15074 if (nodeIsBefore && !nodeIsAfter)
15075 return 2; // left trailed.
15080 // private? - in a new class?
15081 cleanUpPaste : function()
15083 // cleans up the whole document..
15084 Roo.log('cleanuppaste');
15086 this.cleanUpChildren(this.doc.body);
15087 var clean = this.cleanWordChars(this.doc.body.innerHTML);
15088 if (clean != this.doc.body.innerHTML) {
15089 this.doc.body.innerHTML = clean;
15094 cleanWordChars : function(input) {// change the chars to hex code
15095 var he = Roo.HtmlEditorCore;
15097 var output = input;
15098 Roo.each(he.swapCodes, function(sw) {
15099 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
15101 output = output.replace(swapper, sw[1]);
15108 cleanUpChildren : function (n)
15110 if (!n.childNodes.length) {
15113 for (var i = n.childNodes.length-1; i > -1 ; i--) {
15114 this.cleanUpChild(n.childNodes[i]);
15121 cleanUpChild : function (node)
15124 //console.log(node);
15125 if (node.nodeName == "#text") {
15126 // clean up silly Windows -- stuff?
15129 if (node.nodeName == "#comment") {
15130 node.parentNode.removeChild(node);
15131 // clean up silly Windows -- stuff?
15135 if (Roo.HtmlEditorCore.black.indexOf(node.tagName.toLowerCase()) > -1 && this.clearUp) {
15137 node.parentNode.removeChild(node);
15142 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
15144 // remove <a name=....> as rendering on yahoo mailer is borked with this.
15145 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
15147 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
15148 // remove_keep_children = true;
15151 if (remove_keep_children) {
15152 this.cleanUpChildren(node);
15153 // inserts everything just before this node...
15154 while (node.childNodes.length) {
15155 var cn = node.childNodes[0];
15156 node.removeChild(cn);
15157 node.parentNode.insertBefore(cn, node);
15159 node.parentNode.removeChild(node);
15163 if (!node.attributes || !node.attributes.length) {
15164 this.cleanUpChildren(node);
15168 function cleanAttr(n,v)
15171 if (v.match(/^\./) || v.match(/^\//)) {
15174 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
15177 if (v.match(/^#/)) {
15180 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
15181 node.removeAttribute(n);
15185 function cleanStyle(n,v)
15187 if (v.match(/expression/)) { //XSS?? should we even bother..
15188 node.removeAttribute(n);
15191 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.HtmlEditorCore.cwhite : ed.cwhite;
15192 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.HtmlEditorCore.cblack : ed.cblack;
15195 var parts = v.split(/;/);
15198 Roo.each(parts, function(p) {
15199 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
15203 var l = p.split(':').shift().replace(/\s+/g,'');
15204 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
15206 if ( cblack.indexOf(l) > -1) {
15207 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15208 //node.removeAttribute(n);
15212 // only allow 'c whitelisted system attributes'
15213 if ( cwhite.length && cwhite.indexOf(l) < 0) {
15214 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
15215 //node.removeAttribute(n);
15225 if (clean.length) {
15226 node.setAttribute(n, clean.join(';'));
15228 node.removeAttribute(n);
15234 for (var i = node.attributes.length-1; i > -1 ; i--) {
15235 var a = node.attributes[i];
15238 if (a.name.toLowerCase().substr(0,2)=='on') {
15239 node.removeAttribute(a.name);
15242 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
15243 node.removeAttribute(a.name);
15246 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
15247 cleanAttr(a.name,a.value); // fixme..
15250 if (a.name == 'style') {
15251 cleanStyle(a.name,a.value);
15254 /// clean up MS crap..
15255 // tecnically this should be a list of valid class'es..
15258 if (a.name == 'class') {
15259 if (a.value.match(/^Mso/)) {
15260 node.className = '';
15263 if (a.value.match(/body/)) {
15264 node.className = '';
15275 this.cleanUpChildren(node);
15281 // hide stuff that is not compatible
15295 * @event specialkey
15299 * @cfg {String} fieldClass @hide
15302 * @cfg {String} focusClass @hide
15305 * @cfg {String} autoCreate @hide
15308 * @cfg {String} inputType @hide
15311 * @cfg {String} invalidClass @hide
15314 * @cfg {String} invalidText @hide
15317 * @cfg {String} msgFx @hide
15320 * @cfg {String} validateOnBlur @hide
15324 Roo.HtmlEditorCore.white = [
15325 'area', 'br', 'img', 'input', 'hr', 'wbr',
15327 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
15328 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
15329 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
15330 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
15331 'table', 'ul', 'xmp',
15333 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
15336 'dir', 'menu', 'ol', 'ul', 'dl',
15342 Roo.HtmlEditorCore.black = [
15343 // 'embed', 'object', // enable - backend responsiblity to clean thiese
15345 'base', 'basefont', 'bgsound', 'blink', 'body',
15346 'frame', 'frameset', 'head', 'html', 'ilayer',
15347 'iframe', 'layer', 'link', 'meta', 'object',
15348 'script', 'style' ,'title', 'xml' // clean later..
15350 Roo.HtmlEditorCore.clean = [
15351 'script', 'style', 'title', 'xml'
15353 Roo.HtmlEditorCore.remove = [
15358 Roo.HtmlEditorCore.ablack = [
15362 Roo.HtmlEditorCore.aclean = [
15363 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
15367 Roo.HtmlEditorCore.pwhite= [
15368 'http', 'https', 'mailto'
15371 // white listed style attributes.
15372 Roo.HtmlEditorCore.cwhite= [
15373 // 'text-align', /// default is to allow most things..
15379 // black listed style attributes.
15380 Roo.HtmlEditorCore.cblack= [
15381 // 'font-size' -- this can be set by the project
15385 Roo.HtmlEditorCore.swapCodes =[
15404 * @class Roo.bootstrap.HtmlEditor
15405 * @extends Roo.bootstrap.TextArea
15406 * Bootstrap HtmlEditor class
15409 * Create a new HtmlEditor
15410 * @param {Object} config The config object
15413 Roo.bootstrap.HtmlEditor = function(config){
15414 Roo.bootstrap.HtmlEditor.superclass.constructor.call(this, config);
15415 if (!this.toolbars) {
15416 this.toolbars = [];
15418 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
15421 * @event initialize
15422 * Fires when the editor is fully initialized (including the iframe)
15423 * @param {HtmlEditor} this
15428 * Fires when the editor is first receives the focus. Any insertion must wait
15429 * until after this event.
15430 * @param {HtmlEditor} this
15434 * @event beforesync
15435 * Fires before the textarea is updated with content from the editor iframe. Return false
15436 * to cancel the sync.
15437 * @param {HtmlEditor} this
15438 * @param {String} html
15442 * @event beforepush
15443 * Fires before the iframe editor is updated with content from the textarea. Return false
15444 * to cancel the push.
15445 * @param {HtmlEditor} this
15446 * @param {String} html
15451 * Fires when the textarea is updated with content from the editor iframe.
15452 * @param {HtmlEditor} this
15453 * @param {String} html
15458 * Fires when the iframe editor is updated with content from the textarea.
15459 * @param {HtmlEditor} this
15460 * @param {String} html
15464 * @event editmodechange
15465 * Fires when the editor switches edit modes
15466 * @param {HtmlEditor} this
15467 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
15469 editmodechange: true,
15471 * @event editorevent
15472 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
15473 * @param {HtmlEditor} this
15477 * @event firstfocus
15478 * Fires when on first focus - needed by toolbars..
15479 * @param {HtmlEditor} this
15484 * Auto save the htmlEditor value as a file into Events
15485 * @param {HtmlEditor} this
15489 * @event savedpreview
15490 * preview the saved version of htmlEditor
15491 * @param {HtmlEditor} this
15498 Roo.extend(Roo.bootstrap.HtmlEditor, Roo.bootstrap.TextArea, {
15502 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
15507 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
15512 * @cfg {Number} height (in pixels)
15516 * @cfg {Number} width (in pixels)
15521 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
15524 stylesheets: false,
15529 // private properties
15530 validationEvent : false,
15532 initialized : false,
15535 onFocus : Roo.emptyFn,
15537 hideMode:'offsets',
15540 tbContainer : false,
15542 toolbarContainer :function() {
15543 return this.wrap.select('.x-html-editor-tb',true).first();
15547 * Protected method that will not generally be called directly. It
15548 * is called when the editor creates its toolbar. Override this method if you need to
15549 * add custom toolbar buttons.
15550 * @param {HtmlEditor} editor
15552 createToolbar : function(){
15554 Roo.log("create toolbars");
15556 this.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard({editor: this} ) ];
15557 this.toolbars[0].render(this.toolbarContainer());
15561 // if (!editor.toolbars || !editor.toolbars.length) {
15562 // editor.toolbars = [ new Roo.bootstrap.HtmlEditor.ToolbarStandard() ]; // can be empty?
15565 // for (var i =0 ; i < editor.toolbars.length;i++) {
15566 // editor.toolbars[i] = Roo.factory(
15567 // typeof(editor.toolbars[i]) == 'string' ?
15568 // { xtype: editor.toolbars[i]} : editor.toolbars[i],
15569 // Roo.bootstrap.HtmlEditor);
15570 // editor.toolbars[i].init(editor);
15576 onRender : function(ct, position)
15578 // Roo.log("Call onRender: " + this.xtype);
15580 Roo.bootstrap.HtmlEditor.superclass.onRender.call(this, ct, position);
15582 this.wrap = this.inputEl().wrap({
15583 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
15586 this.editorcore.onRender(ct, position);
15588 if (this.resizable) {
15589 this.resizeEl = new Roo.Resizable(this.wrap, {
15593 minHeight : this.height,
15594 height: this.height,
15595 handles : this.resizable,
15598 resize : function(r, w, h) {
15599 _t.onResize(w,h); // -something
15605 this.createToolbar(this);
15608 if(!this.width && this.resizable){
15609 this.setSize(this.wrap.getSize());
15611 if (this.resizeEl) {
15612 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
15613 // should trigger onReize..
15619 onResize : function(w, h)
15621 Roo.log('resize: ' +w + ',' + h );
15622 Roo.bootstrap.HtmlEditor.superclass.onResize.apply(this, arguments);
15626 if(this.inputEl() ){
15627 if(typeof w == 'number'){
15628 var aw = w - this.wrap.getFrameWidth('lr');
15629 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
15632 if(typeof h == 'number'){
15633 var tbh = -11; // fixme it needs to tool bar size!
15634 for (var i =0; i < this.toolbars.length;i++) {
15635 // fixme - ask toolbars for heights?
15636 tbh += this.toolbars[i].el.getHeight();
15637 //if (this.toolbars[i].footer) {
15638 // tbh += this.toolbars[i].footer.el.getHeight();
15646 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
15647 ah -= 5; // knock a few pixes off for look..
15648 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
15652 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
15653 this.editorcore.onResize(ew,eh);
15658 * Toggles the editor between standard and source edit mode.
15659 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
15661 toggleSourceEdit : function(sourceEditMode)
15663 this.editorcore.toggleSourceEdit(sourceEditMode);
15665 if(this.editorcore.sourceEditMode){
15666 Roo.log('editor - showing textarea');
15669 // Roo.log(this.syncValue());
15671 this.inputEl().removeClass('hide');
15672 this.inputEl().dom.removeAttribute('tabIndex');
15673 this.inputEl().focus();
15675 Roo.log('editor - hiding textarea');
15677 // Roo.log(this.pushValue());
15680 this.inputEl().addClass('hide');
15681 this.inputEl().dom.setAttribute('tabIndex', -1);
15682 //this.deferFocus();
15685 if(this.resizable){
15686 this.setSize(this.wrap.getSize());
15689 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
15692 // private (for BoxComponent)
15693 adjustSize : Roo.BoxComponent.prototype.adjustSize,
15695 // private (for BoxComponent)
15696 getResizeEl : function(){
15700 // private (for BoxComponent)
15701 getPositionEl : function(){
15706 initEvents : function(){
15707 this.originalValue = this.getValue();
15711 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15714 // markInvalid : Roo.emptyFn,
15716 // * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
15719 // clearInvalid : Roo.emptyFn,
15721 setValue : function(v){
15722 Roo.bootstrap.HtmlEditor.superclass.setValue.call(this, v);
15723 this.editorcore.pushValue();
15728 deferFocus : function(){
15729 this.focus.defer(10, this);
15733 focus : function(){
15734 this.editorcore.focus();
15740 onDestroy : function(){
15746 for (var i =0; i < this.toolbars.length;i++) {
15747 // fixme - ask toolbars for heights?
15748 this.toolbars[i].onDestroy();
15751 this.wrap.dom.innerHTML = '';
15752 this.wrap.remove();
15757 onFirstFocus : function(){
15758 //Roo.log("onFirstFocus");
15759 this.editorcore.onFirstFocus();
15760 for (var i =0; i < this.toolbars.length;i++) {
15761 this.toolbars[i].onFirstFocus();
15767 syncValue : function()
15769 this.editorcore.syncValue();
15772 pushValue : function()
15774 this.editorcore.pushValue();
15778 // hide stuff that is not compatible
15792 * @event specialkey
15796 * @cfg {String} fieldClass @hide
15799 * @cfg {String} focusClass @hide
15802 * @cfg {String} autoCreate @hide
15805 * @cfg {String} inputType @hide
15808 * @cfg {String} invalidClass @hide
15811 * @cfg {String} invalidText @hide
15814 * @cfg {String} msgFx @hide
15817 * @cfg {String} validateOnBlur @hide
15828 * @class Roo.bootstrap.HtmlEditorToolbar1
15833 new Roo.bootstrap.HtmlEditor({
15836 new Roo.bootstrap.HtmlEditorToolbar1({
15837 disable : { fonts: 1 , format: 1, ..., ... , ...],
15843 * @cfg {Object} disable List of elements to disable..
15844 * @cfg {Array} btns List of additional buttons.
15848 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
15851 Roo.bootstrap.HtmlEditor.ToolbarStandard = function(config)
15854 Roo.apply(this, config);
15856 // default disabled, based on 'good practice'..
15857 this.disable = this.disable || {};
15858 Roo.applyIf(this.disable, {
15861 specialElements : true
15863 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.constructor.call(this, config);
15865 this.editor = config.editor;
15866 this.editorcore = config.editor.editorcore;
15868 this.buttons = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
15870 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
15871 // dont call parent... till later.
15873 Roo.extend(Roo.bootstrap.HtmlEditor.ToolbarStandard, Roo.bootstrap.NavSimplebar, {
15879 editorcore : false,
15884 "h1","h2","h3","h4","h5","h6",
15886 "abbr", "acronym", "address", "cite", "samp", "var",
15890 onRender : function(ct, position)
15892 // Roo.log("Call onRender: " + this.xtype);
15894 Roo.bootstrap.HtmlEditor.ToolbarStandard.superclass.onRender.call(this, ct, position);
15896 this.el.dom.style.marginBottom = '0';
15898 var editorcore = this.editorcore;
15899 var editor= this.editor;
15902 var btn = function(id,cmd , toggle, handler){
15904 var event = toggle ? 'toggle' : 'click';
15909 xns: Roo.bootstrap,
15912 enableToggle:toggle !== false,
15914 pressed : toggle ? false : null,
15917 a.listeners[toggle ? 'toggle' : 'click'] = function() {
15918 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd || id);
15927 xns: Roo.bootstrap,
15928 glyphicon : 'font',
15932 xns: Roo.bootstrap,
15936 Roo.each(this.formats, function(f) {
15937 style.menu.items.push({
15939 xns: Roo.bootstrap,
15940 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
15945 editorcore.insertTag(this.tagname);
15952 children.push(style);
15955 btn('bold',false,true);
15956 btn('italic',false,true);
15957 btn('align-left', 'justifyleft',true);
15958 btn('align-center', 'justifycenter',true);
15959 btn('align-right' , 'justifyright',true);
15960 btn('link', false, false, function(btn) {
15961 //Roo.log("create link?");
15962 var url = prompt(this.createLinkText, this.defaultLinkValue);
15963 if(url && url != 'http:/'+'/'){
15964 this.editorcore.relayCmd('createlink', url);
15967 btn('list','insertunorderedlist',true);
15968 btn('pencil', false,true, function(btn){
15971 this.toggleSourceEdit(btn.pressed);
15977 xns: Roo.bootstrap,
15982 xns: Roo.bootstrap,
15987 cog.menu.items.push({
15989 xns: Roo.bootstrap,
15990 html : Clean styles,
15995 editorcore.insertTag(this.tagname);
16004 this.xtype = 'NavSimplebar';
16006 for(var i=0;i< children.length;i++) {
16008 this.buttons.add(this.addxtypeChild(children[i]));
16012 editor.on('editorevent', this.updateToolbar, this);
16014 onBtnClick : function(id)
16016 this.editorcore.relayCmd(id);
16017 this.editorcore.focus();
16021 * Protected method that will not generally be called directly. It triggers
16022 * a toolbar update by reading the markup state of the current selection in the editor.
16024 updateToolbar: function(){
16026 if(!this.editorcore.activated){
16027 this.editor.onFirstFocus(); // is this neeed?
16031 var btns = this.buttons;
16032 var doc = this.editorcore.doc;
16033 btns.get('bold').setActive(doc.queryCommandState('bold'));
16034 btns.get('italic').setActive(doc.queryCommandState('italic'));
16035 //btns.get('underline').setActive(doc.queryCommandState('underline'));
16037 btns.get('align-left').setActive(doc.queryCommandState('justifyleft'));
16038 btns.get('align-center').setActive(doc.queryCommandState('justifycenter'));
16039 btns.get('align-right').setActive(doc.queryCommandState('justifyright'));
16041 //btns[frameId + '-insertorderedlist').setActive(doc.queryCommandState('insertorderedlist'));
16042 btns.get('list').setActive(doc.queryCommandState('insertunorderedlist'));
16045 var ans = this.editorcore.getAllAncestors();
16046 if (this.formatCombo) {
16049 var store = this.formatCombo.store;
16050 this.formatCombo.setValue("");
16051 for (var i =0; i < ans.length;i++) {
16052 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
16054 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
16062 // hides menus... - so this cant be on a menu...
16063 Roo.bootstrap.MenuMgr.hideAll();
16065 Roo.bootstrap.MenuMgr.hideAll();
16066 //this.editorsyncValue();
16068 onFirstFocus: function() {
16069 this.buttons.each(function(item){
16073 toggleSourceEdit : function(sourceEditMode){
16076 if(sourceEditMode){
16077 Roo.log("disabling buttons");
16078 this.buttons.each( function(item){
16079 if(item.cmd != 'pencil'){
16085 Roo.log("enabling buttons");
16086 if(this.editorcore.initialized){
16087 this.buttons.each( function(item){
16093 Roo.log("calling toggole on editor");
16094 // tell the editor that it's been pressed..
16095 this.editor.toggleSourceEdit(sourceEditMode);
16105 * @class Roo.bootstrap.Table.AbstractSelectionModel
16106 * @extends Roo.util.Observable
16107 * Abstract base class for grid SelectionModels. It provides the interface that should be
16108 * implemented by descendant classes. This class should not be directly instantiated.
16111 Roo.bootstrap.Table.AbstractSelectionModel = function(){
16112 this.locked = false;
16113 Roo.bootstrap.Table.AbstractSelectionModel.superclass.constructor.call(this);
16117 Roo.extend(Roo.bootstrap.Table.AbstractSelectionModel, Roo.util.Observable, {
16118 /** @ignore Called by the grid automatically. Do not call directly. */
16119 init : function(grid){
16125 * Locks the selections.
16128 this.locked = true;
16132 * Unlocks the selections.
16134 unlock : function(){
16135 this.locked = false;
16139 * Returns true if the selections are locked.
16140 * @return {Boolean}
16142 isLocked : function(){
16143 return this.locked;
16147 * @class Roo.bootstrap.Table.ColumnModel
16148 * @extends Roo.util.Observable
16149 * This is the default implementation of a ColumnModel used by the bootstrap table. It defines
16150 * the columns in the table.
16153 * @param {Object} config An Array of column config objects. See this class's
16154 * config objects for details.
16156 Roo.bootstrap.Table.ColumnModel = function(config){
16158 * The config passed into the constructor
16160 this.config = config;
16163 // if no id, create one
16164 // if the column does not have a dataIndex mapping,
16165 // map it to the order it is in the config
16166 for(var i = 0, len = config.length; i < len; i++){
16168 if(typeof c.dataIndex == "undefined"){
16171 if(typeof c.renderer == "string"){
16172 c.renderer = Roo.util.Format[c.renderer];
16174 if(typeof c.id == "undefined"){
16177 // if(c.editor && c.editor.xtype){
16178 // c.editor = Roo.factory(c.editor, Roo.grid);
16180 // if(c.editor && c.editor.isFormField){
16181 // c.editor = new Roo.grid.GridEditor(c.editor);
16184 this.lookup[c.id] = c;
16188 * The width of columns which have no width specified (defaults to 100)
16191 this.defaultWidth = 100;
16194 * Default sortable of columns which have no sortable specified (defaults to false)
16197 this.defaultSortable = false;
16201 * @event widthchange
16202 * Fires when the width of a column changes.
16203 * @param {ColumnModel} this
16204 * @param {Number} columnIndex The column index
16205 * @param {Number} newWidth The new width
16207 "widthchange": true,
16209 * @event headerchange
16210 * Fires when the text of a header changes.
16211 * @param {ColumnModel} this
16212 * @param {Number} columnIndex The column index
16213 * @param {Number} newText The new header text
16215 "headerchange": true,
16217 * @event hiddenchange
16218 * Fires when a column is hidden or "unhidden".
16219 * @param {ColumnModel} this
16220 * @param {Number} columnIndex The column index
16221 * @param {Boolean} hidden true if hidden, false otherwise
16223 "hiddenchange": true,
16225 * @event columnmoved
16226 * Fires when a column is moved.
16227 * @param {ColumnModel} this
16228 * @param {Number} oldIndex
16229 * @param {Number} newIndex
16231 "columnmoved" : true,
16233 * @event columlockchange
16234 * Fires when a column's locked state is changed
16235 * @param {ColumnModel} this
16236 * @param {Number} colIndex
16237 * @param {Boolean} locked true if locked
16239 "columnlockchange" : true
16241 Roo.bootstrap.Table.ColumnModel.superclass.constructor.call(this);
16243 Roo.extend(Roo.bootstrap.Table.ColumnModel, Roo.util.Observable, {
16245 * @cfg {String} header The header text to display in the Grid view.
16248 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
16249 * {@link Roo.data.Record} definition from which to draw the column's value. If not
16250 * specified, the column's index is used as an index into the Record's data Array.
16253 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
16254 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
16257 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
16258 * Defaults to the value of the {@link #defaultSortable} property.
16259 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
16262 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
16265 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
16268 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
16271 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
16274 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
16275 * given the cell's data value. See {@link #setRenderer}. If not specified, the
16276 * default renderer uses the raw data value.
16279 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
16283 * Returns the id of the column at the specified index.
16284 * @param {Number} index The column index
16285 * @return {String} the id
16287 getColumnId : function(index){
16288 return this.config[index].id;
16292 * Returns the column for a specified id.
16293 * @param {String} id The column id
16294 * @return {Object} the column
16296 getColumnById : function(id){
16297 return this.lookup[id];
16302 * Returns the column for a specified dataIndex.
16303 * @param {String} dataIndex The column dataIndex
16304 * @return {Object|Boolean} the column or false if not found
16306 getColumnByDataIndex: function(dataIndex){
16307 var index = this.findColumnIndex(dataIndex);
16308 return index > -1 ? this.config[index] : false;
16312 * Returns the index for a specified column id.
16313 * @param {String} id The column id
16314 * @return {Number} the index, or -1 if not found
16316 getIndexById : function(id){
16317 for(var i = 0, len = this.config.length; i < len; i++){
16318 if(this.config[i].id == id){
16326 * Returns the index for a specified column dataIndex.
16327 * @param {String} dataIndex The column dataIndex
16328 * @return {Number} the index, or -1 if not found
16331 findColumnIndex : function(dataIndex){
16332 for(var i = 0, len = this.config.length; i < len; i++){
16333 if(this.config[i].dataIndex == dataIndex){
16341 moveColumn : function(oldIndex, newIndex){
16342 var c = this.config[oldIndex];
16343 this.config.splice(oldIndex, 1);
16344 this.config.splice(newIndex, 0, c);
16345 this.dataMap = null;
16346 this.fireEvent("columnmoved", this, oldIndex, newIndex);
16349 isLocked : function(colIndex){
16350 return this.config[colIndex].locked === true;
16353 setLocked : function(colIndex, value, suppressEvent){
16354 if(this.isLocked(colIndex) == value){
16357 this.config[colIndex].locked = value;
16358 if(!suppressEvent){
16359 this.fireEvent("columnlockchange", this, colIndex, value);
16363 getTotalLockedWidth : function(){
16364 var totalWidth = 0;
16365 for(var i = 0; i < this.config.length; i++){
16366 if(this.isLocked(i) && !this.isHidden(i)){
16367 this.totalWidth += this.getColumnWidth(i);
16373 getLockedCount : function(){
16374 for(var i = 0, len = this.config.length; i < len; i++){
16375 if(!this.isLocked(i)){
16382 * Returns the number of columns.
16385 getColumnCount : function(visibleOnly){
16386 if(visibleOnly === true){
16388 for(var i = 0, len = this.config.length; i < len; i++){
16389 if(!this.isHidden(i)){
16395 return this.config.length;
16399 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
16400 * @param {Function} fn
16401 * @param {Object} scope (optional)
16402 * @return {Array} result
16404 getColumnsBy : function(fn, scope){
16406 for(var i = 0, len = this.config.length; i < len; i++){
16407 var c = this.config[i];
16408 if(fn.call(scope||this, c, i) === true){
16416 * Returns true if the specified column is sortable.
16417 * @param {Number} col The column index
16418 * @return {Boolean}
16420 isSortable : function(col){
16421 if(typeof this.config[col].sortable == "undefined"){
16422 return this.defaultSortable;
16424 return this.config[col].sortable;
16428 * Returns the rendering (formatting) function defined for the column.
16429 * @param {Number} col The column index.
16430 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
16432 getRenderer : function(col){
16433 if(!this.config[col].renderer){
16434 return Roo.bootstrap.Table.ColumnModel.defaultRenderer;
16436 return this.config[col].renderer;
16440 * Sets the rendering (formatting) function for a column.
16441 * @param {Number} col The column index
16442 * @param {Function} fn The function to use to process the cell's raw data
16443 * to return HTML markup for the grid view. The render function is called with
16444 * the following parameters:<ul>
16445 * <li>Data value.</li>
16446 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
16447 * <li>css A CSS style string to apply to the table cell.</li>
16448 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
16449 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
16450 * <li>Row index</li>
16451 * <li>Column index</li>
16452 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
16454 setRenderer : function(col, fn){
16455 this.config[col].renderer = fn;
16459 * Returns the width for the specified column.
16460 * @param {Number} col The column index
16463 getColumnWidth : function(col){
16464 return this.config[col].width * 1 || this.defaultWidth;
16468 * Sets the width for a column.
16469 * @param {Number} col The column index
16470 * @param {Number} width The new width
16472 setColumnWidth : function(col, width, suppressEvent){
16473 this.config[col].width = width;
16474 this.totalWidth = null;
16475 if(!suppressEvent){
16476 this.fireEvent("widthchange", this, col, width);
16481 * Returns the total width of all columns.
16482 * @param {Boolean} includeHidden True to include hidden column widths
16485 getTotalWidth : function(includeHidden){
16486 if(!this.totalWidth){
16487 this.totalWidth = 0;
16488 for(var i = 0, len = this.config.length; i < len; i++){
16489 if(includeHidden || !this.isHidden(i)){
16490 this.totalWidth += this.getColumnWidth(i);
16494 return this.totalWidth;
16498 * Returns the header for the specified column.
16499 * @param {Number} col The column index
16502 getColumnHeader : function(col){
16503 return this.config[col].header;
16507 * Sets the header for a column.
16508 * @param {Number} col The column index
16509 * @param {String} header The new header
16511 setColumnHeader : function(col, header){
16512 this.config[col].header = header;
16513 this.fireEvent("headerchange", this, col, header);
16517 * Returns the tooltip for the specified column.
16518 * @param {Number} col The column index
16521 getColumnTooltip : function(col){
16522 return this.config[col].tooltip;
16525 * Sets the tooltip for a column.
16526 * @param {Number} col The column index
16527 * @param {String} tooltip The new tooltip
16529 setColumnTooltip : function(col, tooltip){
16530 this.config[col].tooltip = tooltip;
16534 * Returns the dataIndex for the specified column.
16535 * @param {Number} col The column index
16538 getDataIndex : function(col){
16539 return this.config[col].dataIndex;
16543 * Sets the dataIndex for a column.
16544 * @param {Number} col The column index
16545 * @param {Number} dataIndex The new dataIndex
16547 setDataIndex : function(col, dataIndex){
16548 this.config[col].dataIndex = dataIndex;
16554 * Returns true if the cell is editable.
16555 * @param {Number} colIndex The column index
16556 * @param {Number} rowIndex The row index
16557 * @return {Boolean}
16559 isCellEditable : function(colIndex, rowIndex){
16560 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
16564 * Returns the editor defined for the cell/column.
16565 * return false or null to disable editing.
16566 * @param {Number} colIndex The column index
16567 * @param {Number} rowIndex The row index
16570 getCellEditor : function(colIndex, rowIndex){
16571 return this.config[colIndex].editor;
16575 * Sets if a column is editable.
16576 * @param {Number} col The column index
16577 * @param {Boolean} editable True if the column is editable
16579 setEditable : function(col, editable){
16580 this.config[col].editable = editable;
16585 * Returns true if the column is hidden.
16586 * @param {Number} colIndex The column index
16587 * @return {Boolean}
16589 isHidden : function(colIndex){
16590 return this.config[colIndex].hidden;
16595 * Returns true if the column width cannot be changed
16597 isFixed : function(colIndex){
16598 return this.config[colIndex].fixed;
16602 * Returns true if the column can be resized
16603 * @return {Boolean}
16605 isResizable : function(colIndex){
16606 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
16609 * Sets if a column is hidden.
16610 * @param {Number} colIndex The column index
16611 * @param {Boolean} hidden True if the column is hidden
16613 setHidden : function(colIndex, hidden){
16614 this.config[colIndex].hidden = hidden;
16615 this.totalWidth = null;
16616 this.fireEvent("hiddenchange", this, colIndex, hidden);
16620 * Sets the editor for a column.
16621 * @param {Number} col The column index
16622 * @param {Object} editor The editor object
16624 setEditor : function(col, editor){
16625 this.config[col].editor = editor;
16629 Roo.bootstrap.Table.ColumnModel.defaultRenderer = function(value){
16630 if(typeof value == "string" && value.length < 1){
16636 // Alias for backwards compatibility
16637 Roo.bootstrap.Table.DefaultColumnModel = Roo.bootstrap.Table.ColumnModel;
16640 * @extends Roo.bootstrap.Table.AbstractSelectionModel
16641 * @class Roo.bootstrap.Table.RowSelectionModel
16642 * The default SelectionModel used by {@link Roo.bootstrap.Table}.
16643 * It supports multiple selections and keyboard selection/navigation.
16645 * @param {Object} config
16648 Roo.bootstrap.Table.RowSelectionModel = function(config){
16649 Roo.apply(this, config);
16650 this.selections = new Roo.util.MixedCollection(false, function(o){
16655 this.lastActive = false;
16659 * @event selectionchange
16660 * Fires when the selection changes
16661 * @param {SelectionModel} this
16663 "selectionchange" : true,
16665 * @event afterselectionchange
16666 * Fires after the selection changes (eg. by key press or clicking)
16667 * @param {SelectionModel} this
16669 "afterselectionchange" : true,
16671 * @event beforerowselect
16672 * Fires when a row is selected being selected, return false to cancel.
16673 * @param {SelectionModel} this
16674 * @param {Number} rowIndex The selected index
16675 * @param {Boolean} keepExisting False if other selections will be cleared
16677 "beforerowselect" : true,
16680 * Fires when a row is selected.
16681 * @param {SelectionModel} this
16682 * @param {Number} rowIndex The selected index
16683 * @param {Roo.data.Record} r The record
16685 "rowselect" : true,
16687 * @event rowdeselect
16688 * Fires when a row is deselected.
16689 * @param {SelectionModel} this
16690 * @param {Number} rowIndex The selected index
16692 "rowdeselect" : true
16694 Roo.bootstrap.Table.RowSelectionModel.superclass.constructor.call(this);
16695 this.locked = false;
16698 Roo.extend(Roo.bootstrap.Table.RowSelectionModel, Roo.bootstrap.Table.AbstractSelectionModel, {
16700 * @cfg {Boolean} singleSelect
16701 * True to allow selection of only one row at a time (defaults to false)
16703 singleSelect : false,
16706 initEvents : function(){
16708 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
16709 this.grid.on("mousedown", this.handleMouseDown, this);
16710 }else{ // allow click to work like normal
16711 this.grid.on("rowclick", this.handleDragableRowClick, this);
16714 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
16715 "up" : function(e){
16717 this.selectPrevious(e.shiftKey);
16718 }else if(this.last !== false && this.lastActive !== false){
16719 var last = this.last;
16720 this.selectRange(this.last, this.lastActive-1);
16721 this.grid.getView().focusRow(this.lastActive);
16722 if(last !== false){
16726 this.selectFirstRow();
16728 this.fireEvent("afterselectionchange", this);
16730 "down" : function(e){
16732 this.selectNext(e.shiftKey);
16733 }else if(this.last !== false && this.lastActive !== false){
16734 var last = this.last;
16735 this.selectRange(this.last, this.lastActive+1);
16736 this.grid.getView().focusRow(this.lastActive);
16737 if(last !== false){
16741 this.selectFirstRow();
16743 this.fireEvent("afterselectionchange", this);
16748 var view = this.grid.view;
16749 view.on("refresh", this.onRefresh, this);
16750 view.on("rowupdated", this.onRowUpdated, this);
16751 view.on("rowremoved", this.onRemove, this);
16755 onRefresh : function(){
16756 var ds = this.grid.dataSource, i, v = this.grid.view;
16757 var s = this.selections;
16758 s.each(function(r){
16759 if((i = ds.indexOfId(r.id)) != -1){
16768 onRemove : function(v, index, r){
16769 this.selections.remove(r);
16773 onRowUpdated : function(v, index, r){
16774 if(this.isSelected(r)){
16775 v.onRowSelect(index);
16781 * @param {Array} records The records to select
16782 * @param {Boolean} keepExisting (optional) True to keep existing selections
16784 selectRecords : function(records, keepExisting){
16786 this.clearSelections();
16788 var ds = this.grid.dataSource;
16789 for(var i = 0, len = records.length; i < len; i++){
16790 this.selectRow(ds.indexOf(records[i]), true);
16795 * Gets the number of selected rows.
16798 getCount : function(){
16799 return this.selections.length;
16803 * Selects the first row in the grid.
16805 selectFirstRow : function(){
16810 * Select the last row.
16811 * @param {Boolean} keepExisting (optional) True to keep existing selections
16813 selectLastRow : function(keepExisting){
16814 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
16818 * Selects the row immediately following the last selected row.
16819 * @param {Boolean} keepExisting (optional) True to keep existing selections
16821 selectNext : function(keepExisting){
16822 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
16823 this.selectRow(this.last+1, keepExisting);
16824 this.grid.getView().focusRow(this.last);
16829 * Selects the row that precedes the last selected row.
16830 * @param {Boolean} keepExisting (optional) True to keep existing selections
16832 selectPrevious : function(keepExisting){
16834 this.selectRow(this.last-1, keepExisting);
16835 this.grid.getView().focusRow(this.last);
16840 * Returns the selected records
16841 * @return {Array} Array of selected records
16843 getSelections : function(){
16844 return [].concat(this.selections.items);
16848 * Returns the first selected record.
16851 getSelected : function(){
16852 return this.selections.itemAt(0);
16857 * Clears all selections.
16859 clearSelections : function(fast){
16860 if(this.locked) return;
16862 var ds = this.grid.dataSource;
16863 var s = this.selections;
16864 s.each(function(r){
16865 this.deselectRow(ds.indexOfId(r.id));
16869 this.selections.clear();
16876 * Selects all rows.
16878 selectAll : function(){
16879 if(this.locked) return;
16880 this.selections.clear();
16881 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
16882 this.selectRow(i, true);
16887 * Returns True if there is a selection.
16888 * @return {Boolean}
16890 hasSelection : function(){
16891 return this.selections.length > 0;
16895 * Returns True if the specified row is selected.
16896 * @param {Number/Record} record The record or index of the record to check
16897 * @return {Boolean}
16899 isSelected : function(index){
16900 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
16901 return (r && this.selections.key(r.id) ? true : false);
16905 * Returns True if the specified record id is selected.
16906 * @param {String} id The id of record to check
16907 * @return {Boolean}
16909 isIdSelected : function(id){
16910 return (this.selections.key(id) ? true : false);
16914 handleMouseDown : function(e, t){
16915 var view = this.grid.getView(), rowIndex;
16916 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
16919 if(e.shiftKey && this.last !== false){
16920 var last = this.last;
16921 this.selectRange(last, rowIndex, e.ctrlKey);
16922 this.last = last; // reset the last
16923 view.focusRow(rowIndex);
16925 var isSelected = this.isSelected(rowIndex);
16926 if(e.button !== 0 && isSelected){
16927 view.focusRow(rowIndex);
16928 }else if(e.ctrlKey && isSelected){
16929 this.deselectRow(rowIndex);
16930 }else if(!isSelected){
16931 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
16932 view.focusRow(rowIndex);
16935 this.fireEvent("afterselectionchange", this);
16938 handleDragableRowClick : function(grid, rowIndex, e)
16940 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
16941 this.selectRow(rowIndex, false);
16942 grid.view.focusRow(rowIndex);
16943 this.fireEvent("afterselectionchange", this);
16948 * Selects multiple rows.
16949 * @param {Array} rows Array of the indexes of the row to select
16950 * @param {Boolean} keepExisting (optional) True to keep existing selections
16952 selectRows : function(rows, keepExisting){
16954 this.clearSelections();
16956 for(var i = 0, len = rows.length; i < len; i++){
16957 this.selectRow(rows[i], true);
16962 * Selects a range of rows. All rows in between startRow and endRow are also selected.
16963 * @param {Number} startRow The index of the first row in the range
16964 * @param {Number} endRow The index of the last row in the range
16965 * @param {Boolean} keepExisting (optional) True to retain existing selections
16967 selectRange : function(startRow, endRow, keepExisting){
16968 if(this.locked) return;
16970 this.clearSelections();
16972 if(startRow <= endRow){
16973 for(var i = startRow; i <= endRow; i++){
16974 this.selectRow(i, true);
16977 for(var i = startRow; i >= endRow; i--){
16978 this.selectRow(i, true);
16984 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
16985 * @param {Number} startRow The index of the first row in the range
16986 * @param {Number} endRow The index of the last row in the range
16988 deselectRange : function(startRow, endRow, preventViewNotify){
16989 if(this.locked) return;
16990 for(var i = startRow; i <= endRow; i++){
16991 this.deselectRow(i, preventViewNotify);
16997 * @param {Number} row The index of the row to select
16998 * @param {Boolean} keepExisting (optional) True to keep existing selections
17000 selectRow : function(index, keepExisting, preventViewNotify){
17001 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
17002 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
17003 if(!keepExisting || this.singleSelect){
17004 this.clearSelections();
17006 var r = this.grid.dataSource.getAt(index);
17007 this.selections.add(r);
17008 this.last = this.lastActive = index;
17009 if(!preventViewNotify){
17010 this.grid.getView().onRowSelect(index);
17012 this.fireEvent("rowselect", this, index, r);
17013 this.fireEvent("selectionchange", this);
17019 * @param {Number} row The index of the row to deselect
17021 deselectRow : function(index, preventViewNotify){
17022 if(this.locked) return;
17023 if(this.last == index){
17026 if(this.lastActive == index){
17027 this.lastActive = false;
17029 var r = this.grid.dataSource.getAt(index);
17030 this.selections.remove(r);
17031 if(!preventViewNotify){
17032 this.grid.getView().onRowDeselect(index);
17034 this.fireEvent("rowdeselect", this, index);
17035 this.fireEvent("selectionchange", this);
17039 restoreLast : function(){
17041 this.last = this._last;
17046 acceptsNav : function(row, col, cm){
17047 return !cm.isHidden(col) && cm.isCellEditable(col, row);
17051 onEditorKey : function(field, e){
17052 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
17057 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
17059 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
17061 }else if(k == e.ENTER && !e.ctrlKey){
17065 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
17067 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
17069 }else if(k == e.ESC){
17073 g.startEditing(newCell[0], newCell[1]);
17084 * @class Roo.bootstrap.MessageBar
17085 * @extends Roo.bootstrap.Component
17086 * Bootstrap MessageBar class
17087 * @cfg {String} html contents of the MessageBar
17088 * @cfg {String} weight (info | success | warning | danger) default info
17089 * @cfg {String} beforeClass insert the bar before the given class
17090 * @cfg {Boolean} closable (true | false) default false
17091 * @cfg {Boolean} fixed (true | false) default false, fix the bar at the top
17094 * Create a new Element
17095 * @param {Object} config The config object
17098 Roo.bootstrap.MessageBar = function(config){
17099 Roo.bootstrap.MessageBar.superclass.constructor.call(this, config);
17102 Roo.extend(Roo.bootstrap.MessageBar, Roo.bootstrap.Component, {
17108 beforeClass: 'bootstrap-sticky-wrap',
17110 getAutoCreate : function(){
17114 cls: 'alert alert-dismissable alert-' + this.weight,
17119 html: this.html || ''
17125 cfg.cls += ' alert-messages-fixed';
17139 onRender : function(ct, position)
17141 Roo.bootstrap.Component.superclass.onRender.call(this, ct, position);
17144 var cfg = Roo.apply({}, this.getAutoCreate());
17148 cfg.cls += ' ' + this.cls;
17151 cfg.style = this.style;
17153 this.el = Roo.get(document.body).createChild(cfg, Roo.select('.'+this.beforeClass, true).first());
17155 this.el.setVisibilityMode(Roo.Element.DISPLAY);
17158 this.el.select('>button.close').on('click', this.hide, this);
17164 if (!this.rendered) {
17170 this.fireEvent('show', this);
17176 if (!this.rendered) {
17182 this.fireEvent('hide', this);
17185 update : function()
17187 // var e = this.el.dom.firstChild;
17189 // if(this.closable){
17190 // e = e.nextSibling;
17193 // e.data = this.html || '';
17195 this.el.select('>.message', true).first().dom.innerHTML = this.html || '';