`
langgufu
  • 浏览: 2317612 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Ext 多选下拉 MultiComBox

阅读更多

下面介绍MultiComboBox的使用方式,大家先看看下面的代码:

Java代码
  1. Ext.onReady(function(){
  2. var formPanel = new Ext.FormPanel({
  3. height : 100,// 表单面板的高度
  4. width : 400,// 表单面板的宽度
  5. labelWidth : 120,// 字段标签宽度
  6. labelAlign : "right",// 字段标签对齐方式
  7. fileUpload: true,//支持文件上传
  8. defaults : {// 默认form元素类型为textfield
  9. xtype : "textfield",// 默认类型为textfield
  10. width : 150 // 默认宽度
  11. },
  12. items : [{
  13. xtype:'multicombo',
  14. width:250,
  15. store: new Ext.data.SimpleStore({
  16. fields: ["name","value"],
  17. data:[['测试菜单1',1],['测试菜单2',2],['测试菜单3',3],['测试菜单4',4]]}),
  18. valueField :"value",
  19. displayField: "name",
  20. labelSeparator:':',
  21. displaySeparator:';',
  22. valueSeparator:',',
  23. mode: 'local',
  24. value:'1,2',
  25. forceSelection: true,
  26. hiddenName:'test',
  27. editable: true,
  28. triggerAction: 'all',
  29. allowBlank:false,
  30. emptyText:'请选择',
  31. fieldLabel: '多选下拉ComBo'
  32. }],
  33. buttons : [{
  34. text : '提交',
  35. type : 'submit',
  36. handler : function() {
  37. }
  38. }]
  39. });
  40. formPanel.render("multicombo-div");
  41. });
  1. <span class="hilite1">Ext</span>
  2. .onReady(function(){
  3. var formPanel = new <span class="hilite1">Ext</span>
  4. .FormPanel({
  5. height : 100,// 表单面板的高度
  6. width : 400,// 表单面板的宽度
  7. labelWidth : 120,// 字段标签宽度
  8. labelAlign : "right",// 字段标签对齐方式
  9. fileUpload: true,//支持文件上传
  10. defaults : {// 默认form元素类型为textfield
  11. xtype : "textfield",// 默认类型为textfield
  12. width : 150 // 默认宽度
  13. },
  14. items : [{
  15. xtype:'multicombo',
  16. width:250,
  17. store: new <span class="hilite1">Ext</span>
  18. .data.SimpleStore({
  19. fields: ["name","value"],
  20. data:[['测试菜单1',1],['测试菜单2',2],['测试菜单3',3],['测试菜单4',4]]}),
  21. valueField :"value",
  22. displayField: "name",
  23. labelSeparator:':',
  24. displaySeparator:';',
  25. valueSeparator:',',
  26. mode: 'local',
  27. value:'1,2',
  28. forceSelection: true,
  29. hiddenName:'test',
  30. editable: true,
  31. triggerAction: 'all',
  32. allowBlank:false,
  33. emptyText:'请选择',
  34. fieldLabel: '多选下拉ComBo'
  35. }],
  36. buttons : [{
  37. text : '提交',
  38. type : 'submit',
  39. handler : function() {
  40. }
  41. }]
  42. });
  43. formPanel.render("multicombo-div");
  44. });
Ext
.onReady(function(){
   	  	  var formPanel = new Ext
.FormPanel({
			height : 100,// 表单面板的高度
			width : 400,// 表单面板的宽度
			labelWidth : 120,// 字段标签宽度
			labelAlign : "right",// 字段标签对齐方式
			fileUpload: true,//支持文件上传
			defaults : {// 默认form元素类型为textfield
				xtype : "textfield",// 默认类型为textfield
				width : 150 // 默认宽度
			},
			items : [{
			   xtype:'multicombo',
			   width:250,
			   store: new Ext
.data.SimpleStore({
			       fields: ["name","value"],
			       data:[['测试菜单1',1],['测试菜单2',2],['测试菜单3',3],['测试菜单4',4]]}),
			   valueField :"value",
			   displayField: "name",
			   labelSeparator:':',
			   displaySeparator:';',
			   valueSeparator:',',
			   mode: 'local',
			   value:'1,2',
			   forceSelection: true,
			   hiddenName:'test',
			   editable: true,
			   triggerAction: 'all',
			   allowBlank:false,
			   emptyText:'请选择',
			   fieldLabel: '多选下拉ComBo'
			}],		
			buttons : [{
				text : '提交',
				type : 'submit',
				handler : function() {
					
				}
			}]
		});
		formPanel.render("multicombo-div");
});



由上面代码可以看到用法大致和ComboBox一样,不相同的地方是:

Java代码
  1. xtype:'multicombo',//MultiComboBox注册类型名称
  2. displaySeparator:';',//多选显示分隔字符
  3. valueSeparator:',',//多选提交到后台的值分隔符
  4. value:'1,2',// 多值通过","分隔,与valueSeparator相对应,表示默认选择了"测试菜单1'"和"测试菜单2"
  1. xtype:'multicombo',//MultiComboBox注册类型名称
  2. displaySeparator:';',//多选显示分隔字符
  3. valueSeparator:',',//多选提交到后台的值分隔符
  4. value:'1,2',// 多值通过","分隔,与valueSeparator相对应,表示默认选择了"测试菜单1'"和"测试菜单2"
xtype:'multicombo',//MultiComboBox注册类型名称
displaySeparator:';',//多选显示分隔字符
valueSeparator:',',//多选提交到后台的值分隔符
value:'1,2',//  多值通过","分隔,与valueSeparator相对应,表示默认选择了"测试菜单1'"和"测试菜单2"



由于添加了多选CheckBox图标,所以需要在ext-all.css文件最后添加两行支持样式:

Java代码
  1. .checked{background-image:url(../images/default/menu/checked.gif)}
  2. .unchecked{background-image:url(../images/default/menu/unchecked.gif)}
  1. .checked{background-image:url(../images/default/menu/checked.gif)}
  2. .unchecked{background-image:url(../images/default/menu/unchecked.gif)}
.checked{background-image:url(../images/default/menu/checked.gif)}
.unchecked{background-image:url(../images/default/menu/unchecked.gif)}



MultiComboBox的源代码:

Java代码
  1. Ext.form.MultiComboBox = Ext.extend(Ext.form.TriggerField, {
  2. defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
  3. listClass: '',
  4. selectedClass: 'x-combo-selected',
  5. triggerClass : 'x-form-arrow-trigger',
  6. shadow:'sides',
  7. listAlign: 'tl-bl?',
  8. maxHeight: 300,
  9. triggerAction: 'query',
  10. minChars : 4,
  11. typeAhead: false,
  12. queryDelay: 500,
  13. pageSize: 0,
  14. selectOnFocus:false,
  15. queryParam: 'query',
  16. loadingText: 'Loading...',
  17. resizable: false,
  18. handleHeight : 8,
  19. editable: true,
  20. allQuery: '',
  21. mode: 'remote',
  22. minListWidth : 70,
  23. forceSelection:false,
  24. typeAheadDelay : 250,
  25. displaySeparator:';',
  26. valueSeparator:',',
  27. lazyInit : true,
  28. initComponent : function(){
  29. Ext.form.ComboBox.superclass.initComponent.call(this);
  30. this.addEvents(
  31. 'expand',
  32. 'collapse',
  33. 'beforeselect',
  34. 'select',
  35. 'beforequery'
  36. );
  37. if(this.transform){
  38. this.allowDomMove = false;
  39. var s = Ext.getDom(this.transform);
  40. if(!this.hiddenName){
  41. this.hiddenName = s.name;
  42. }
  43. if(!this.store){
  44. this.mode = 'local';
  45. var d = [], opts = s.options;
  46. for(var i = 0, len = opts.length;i < len; i++){
  47. var o = opts[i];
  48. var value = (Ext.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
  49. if(o.selected) {
  50. this.value = value;
  51. }
  52. d.push([value, o.text]);
  53. }
  54. this.store = new Ext.data.SimpleStore({
  55. 'id': 0,
  56. fields: ['value', 'text'],
  57. data : d
  58. });
  59. this.valueField = 'value';
  60. this.displayField = 'text';
  61. }
  62. s.name = Ext.id(); // wipe out the name in case somewhere else they have a reference
  63. if(!this.lazyRender){
  64. this.target = true;
  65. this.el = Ext.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
  66. Ext.removeNode(s); // remove it
  67. this.render(this.el.parentNode);
  68. }else{
  69. Ext.removeNode(s); // remove it
  70. }
  71. }
  72. this.selectedIndex = -1;
  73. if(this.mode == 'local'){
  74. if(this.initialConfig.queryDelay === undefined){
  75. this.queryDelay = 10;
  76. }
  77. if(this.initialConfig.minChars === undefined){
  78. this.minChars = 0;
  79. }
  80. }
  81. },
  82. // private
  83. onRender : function(ct, position){
  84. Ext.form.ComboBox.superclass.onRender.call(this, ct, position);
  85. var disValue="";
  86. if(this.hiddenName){
  87. this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
  88. 'before', true);
  89. var hvalue=this.hiddenValue !== undefined ? this.hiddenValue :
  90. this.value !== undefined ? this.value : '';
  91. var hvalueArray=hvalue.split(this.valueSeparator);
  92. for(var i=0;i<this.store.data.length;i++){
  93. var r = this.store.getAt(i);
  94. var newValue = r.data[this.displayField];
  95. var v=r.data[this.valueField];
  96. for(var j=0;j<hvalueArray.length;j++){
  97. if(hvalueArray[j]==v){
  98. disValue+=newValue+this.displaySeparator;
  99. }
  100. }
  101. }
  102. this.hiddenField.value =this.hiddenValue !== undefined ? this.hiddenValue :
  103. this.value !== undefined ? this.value : '';
  104. this.el.dom.removeAttribute('name');
  105. }
  106. if(Ext.isGecko){
  107. this.el.dom.setAttribute('autocomplete', 'off');
  108. }
  109. if(!this.lazyInit){
  110. this.initList();
  111. }else{
  112. this.on('focus', this.initList, this, {single: true});
  113. }
  114. if(!this.editable){
  115. this.editable = true;
  116. this.setEditable(false);
  117. }
  118. this.setValue(disValue);
  119. },
  120. initList : function(){
  121. if(!this.list){
  122. var cls = 'x-combo-list';
  123. this.list = new Ext.Layer({
  124. shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
  125. });
  126. var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
  127. this.list.setWidth(lw);
  128. this.list.swallowEvent('mousewheel');
  129. this.assetHeight = 0;
  130. if(this.title){
  131. this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
  132. this.assetHeight += this.header.getHeight();
  133. }
  134. this.innerList = this.list.createChild({cls:cls+'-inner'});
  135. this.innerList.on('mouseover', this.onViewOver, this);
  136. this.innerList.on('mousemove', this.onViewMove, this);
  137. this.innerList.setWidth(lw - this.list.getFrameWidth('lr'))
  138. if(this.pageSize){
  139. this.footer = this.list.createChild({cls:cls+'-ft'});
  140. this.pageTb = new Ext.PagingToolbar({
  141. store:this.store,
  142. pageSize: this.pageSize,
  143. renderTo:this.footer
  144. });
  145. this.assetHeight += this.footer.getHeight();
  146. }
  147. if(!this.tpl){
  148. //alert(cls);
  149. //x-combo-list-item
  150. this.tpl = '<tpl for="."><div class="'+cls+'-item"><span class="unchecked" id="checkBox_{' + this.displayField + '}"+ width="20">&nbsp;&nbsp;&nbsp;&nbsp;</span>{' + this.displayField + '}</div></tpl>';
  151. }
  152. this.view = new Ext.DataView({
  153. applyTo: this.innerList,
  154. tpl: this.tpl,
  155. singleSelect: true,
  156. selectedClass: this.selectedClass,
  157. itemSelector: this.itemSelector || '.' + cls + '-item'
  158. });
  159. this.view.on('click', this.onViewClick, this);
  160. this.bindStore(this.store, true);
  161. if(this.resizable){
  162. this.resizer = new Ext.Resizable(this.list, {
  163. pinned:true, handles:'se'
  164. });
  165. this.resizer.on('resize', function(r, w, h){
  166. this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
  167. this.listWidth = w;
  168. this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
  169. this.restrictHeight();
  170. }, this);
  171. this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
  172. }
  173. }
  174. },
  175. bindStore : function(store, initial){
  176. if(this.store && !initial){
  177. this.store.un('beforeload', this.onBeforeLoad, this);
  178. this.store.un('load', this.onLoad, this);
  179. this.store.un('loadexception', this.collapse, this);
  180. if(!store){
  181. this.store = null;
  182. if(this.view){
  183. this.view.setStore(null);
  184. }
  185. }
  186. }
  187. if(store){
  188. this.store = Ext.StoreMgr.lookup(store);
  189. this.store.on('beforeload', this.onBeforeLoad, this);
  190. this.store.on('load', this.onLoad, this);
  191. this.store.on('loadexception', this.collapse, this);
  192. if(this.view){
  193. this.view.setStore(store);
  194. }
  195. }
  196. },
  197. // private
  198. initEvents : function(){
  199. Ext.form.ComboBox.superclass.initEvents.call(this);
  200. this.keyNav = new Ext.KeyNav(this.el, {
  201. "up" : function(e){
  202. this.inKeyMode = true;
  203. this.selectPrev();
  204. },
  205. "down" : function(e){
  206. if(!this.isExpanded()){
  207. this.onTriggerClick();
  208. }else{
  209. this.inKeyMode = true;
  210. this.selectNext();
  211. }
  212. },
  213. "enter" : function(e){
  214. this.onViewClick();
  215. //return true;
  216. },
  217. "esc" : function(e){
  218. this.collapse();
  219. },
  220. "tab" : function(e){
  221. this.onViewClick(false);
  222. return true;
  223. },
  224. scope : this,
  225. doRelay : function(foo, bar, hname){
  226. if(hname == 'down' || this.scope.isExpanded()){
  227. return Ext.KeyNav.prototype.doRelay.apply(this, arguments);
  228. }
  229. return true;
  230. },
  231. forceKeyDown : true
  232. });
  233. this.queryDelay = Math.max(this.queryDelay || 10,
  234. this.mode == 'local' ? 10 : 250);
  235. this.dqTask = new Ext.util.DelayedTask(this.initQuery, this);
  236. if(this.typeAhead){
  237. this.taTask = new Ext.util.DelayedTask(this.onTypeAhead, this);
  238. }
  239. if(this.editable !== false){
  240. this.el.on("keyup", this.onKeyUp, this);
  241. }
  242. if(this.forceSelection){
  243. this.on('blur', this.doForce, this);
  244. }
  245. },
  246. onDestroy : function(){
  247. if(this.view){
  248. this.view.el.removeAllListeners();
  249. this.view.el.remove();
  250. this.view.purgeListeners();
  251. }
  252. if(this.list){
  253. this.list.destroy();
  254. }
  255. this.bindStore(null);
  256. Ext.form.ComboBox.superclass.onDestroy.call(this);
  257. },
  258. // private
  259. fireKey : function(e){
  260. if(e.isNavKeyPress() && !this.list.isVisible()){
  261. this.fireEvent("specialkey", this, e);
  262. }
  263. },
  264. // private
  265. onResize: function(w, h){
  266. Ext.form.ComboBox.superclass.onResize.apply(this, arguments);
  267. if(this.list && this.listWidth === undefined){
  268. var lw = Math.max(w, this.minListWidth);
  269. this.list.setWidth(lw);
  270. this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
  271. }
  272. },
  273. // private
  274. onDisable: function(){
  275. Ext.form.ComboBox.superclass.onDisable.apply(this, arguments);
  276. if(this.hiddenField){
  277. this.hiddenField.disabled = this.disabled;
  278. }
  279. },
  280. setEditable : function(value){
  281. if(value == this.editable){
  282. return;
  283. }
  284. this.editable = value;
  285. if(!value){
  286. this.el.dom.setAttribute('readOnly', true);
  287. this.el.on('mousedown', this.onTriggerClick, this);
  288. this.el.addClass('x-combo-noedit');
  289. }else{
  290. this.el.dom.setAttribute('readOnly', false);
  291. this.el.un('mousedown', this.onTriggerClick, this);
  292. this.el.removeClass('x-combo-noedit');
  293. }
  294. },
  295. // private
  296. onBeforeLoad : function(){
  297. if(!this.hasFocus){
  298. return;
  299. }
  300. this.innerList.update(this.loadingText ?
  301. '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
  302. this.restrictHeight();
  303. this.selectedIndex = -1;
  304. },
  305. // private
  306. onLoad : function(){
  307. if(!this.hasFocus){
  308. return;
  309. }
  310. if(this.store.getCount() > 0){
  311. this.expand();
  312. this.restrictHeight();
  313. if(this.lastQuery == this.allQuery){
  314. if(this.editable){
  315. this.el.dom.select();
  316. }
  317. if(!this.selectByValue(this.value, true)){
  318. this.select(0, true);
  319. }
  320. }else{
  321. this.selectNext();
  322. if(this.typeAhead && this.lastKey != Ext.EventObject.BACKSPACE && this.lastKey != Ext.EventObject.DELETE){
  323. this.taTask.delay(this.typeAheadDelay);
  324. }
  325. }
  326. }else{
  327. this.onEmptyResults();
  328. }
  329. },
  330. // private
  331. onTypeAhead : function(){
  332. if(this.store.getCount() > 0){
  333. var r = this.store.getAt(0);
  334. var newValue = r.data[this.displayField];
  335. var len = newValue.length;
  336. var selStart = this.getRawValue().length;
  337. if(selStart != len){
  338. this.setRawValue(newValue);
  339. this.selectText(selStart, newValue.length);
  340. }
  341. }
  342. },
  343. // private
  344. onSelect : function(record, index){
  345. if(this.fireEvent('beforeselect', this, record, index) !== false){
  346. var r = this.store.getAt(index);
  347. var newValue = r.data[this.displayField];
  348. var check=document.getElementById("checkBox_"+newValue);
  349. if(check.className=="checked"){
  350. check.className="unchecked"
  351. }else{
  352. check.className="checked"
  353. }
  354. var value="";
  355. var hiddenValue="";
  356. for(var i=0;i<this.store.data.length;i++){
  357. var r = this.store.getAt(i);
  358. newValue = r.data[this.displayField];
  359. check=document.getElementById("checkBox_"+newValue);
  360. if(check.className=="checked"){
  361. value+= r.data[this.displayField]+this.displaySeparator;
  362. hiddenValue+= r.data[this.valueField]+this.valueSeparator;
  363. }
  364. }
  365. if(value.length>1){
  366. value=value.substring(0,value.length-this.displaySeparator.length);
  367. }
  368. if(hiddenValue.length>1){
  369. hiddenValue=hiddenValue.substring(0,value.length-this.valueSeparator.length);
  370. }
  371. this.setValue(value);
  372. this.hiddenField.value=hiddenValue;
  373. this.fireEvent('select', this, record, index);
  374. }
  375. },
  376. getValue : function(){
  377. if(this.valueField){
  378. return typeof this.value != 'undefined' ? this.value : '';
  379. }else{
  380. return Ext.form.ComboBox.superclass.getValue.call(this);
  381. }
  382. },
  383. /**
  384. * Clears any text/value currently set in the field
  385. */
  386. clearValue : function(){
  387. if(this.hiddenField){
  388. this.hiddenField.value = '';
  389. }
  390. this.setRawValue('');
  391. this.lastSelectionText = '';
  392. this.applyEmptyText();
  393. },
  394. setValue : function(v){
  395. var text = v;
  396. if(this.valueField){
  397. var r = this.findRecord(this.valueField, v);
  398. if(r){
  399. text = r.data[this.displayField];
  400. }else if(this.valueNotFoundText !== undefined){
  401. text = this.valueNotFoundText;
  402. }
  403. }
  404. this.lastSelectionText = text;
  405. Ext.form.ComboBox.superclass.setValue.call(this, text);
  406. this.value = v;
  407. },
  408. // private
  409. findRecord : function(prop, value){
  410. var record;
  411. if(this.store.getCount() > 0){
  412. this.store.each(function(r){
  413. if(r.data[prop] == value){
  414. record = r;
  415. return false;
  416. }
  417. });
  418. }
  419. return record;
  420. },
  421. // private
  422. onViewMove : function(e, t){
  423. this.inKeyMode = false;
  424. },
  425. // private
  426. onViewOver : function(e, t){
  427. if(this.inKeyMode){ // prevent key nav and mouse over conflicts
  428. return;
  429. }
  430. var item = this.view.findItemFromChild(t);
  431. if(item){
  432. var index = this.view.indexOf(item);
  433. this.select(index, false);
  434. }
  435. },
  436. // private
  437. onViewClick : function(doFocus){
  438. var index = this.view.getSelectedIndexes()[0];
  439. var r = this.store.getAt(index);
  440. if(r){
  441. this.onSelect(r, index);
  442. }
  443. if(doFocus !== false){
  444. this.el.focus();
  445. }
  446. },
  447. // private
  448. restrictHeight : function(){
  449. this.innerList.dom.style.height = '';
  450. var inner = this.innerList.dom;
  451. var fw = this.list.getFrameWidth('tb');
  452. var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
  453. this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
  454. this.list.beginUpdate();
  455. this.list.setHeight(this.innerList.getHeight()+fw+(this.resizable?this.handleHeight:0)+this.assetHeight);
  456. this.list.alignTo(this.el, this.listAlign);
  457. this.list.endUpdate();
  458. },
  459. // private
  460. onEmptyResults : function(){
  461. this.collapse();
  462. },
  463. /**
  464. * Returns true if the dropdown list is expanded, else false.
  465. */
  466. isExpanded : function(){
  467. return this.list && this.list.isVisible();
  468. },
  469. selectByValue : function(v, scrollIntoView){
  470. if(v !== undefined && v !== null){
  471. var r = this.findRecord(this.valueField || this.displayField, v);
  472. if(r){
  473. this.select(this.store.indexOf(r), scrollIntoView);
  474. return true;
  475. }
  476. }
  477. return false;
  478. },
  479. select : function(index, scrollIntoView){
  480. this.selectedIndex = index;
  481. this.view.select(index);
  482. if(scrollIntoView !== false){
  483. var el = this.view.getNode(index);
  484. if(el){
  485. this.innerList.scrollChildIntoView(el, false);
  486. }
  487. }
  488. },
  489. // private
  490. selectNext : function(){
  491. var ct = this.store.getCount();
  492. if(ct > 0){
  493. if(this.selectedIndex == -1){
  494. this.select(0);
  495. }else if(this.selectedIndex < ct-1){
  496. this.select(this.selectedIndex+1);
  497. }
  498. }
  499. },
  500. // private
  501. selectPrev : function(){
  502. var ct = this.store.getCount();
  503. if(ct > 0){
  504. if(this.selectedIndex == -1){
  505. this.select(0);
  506. }else if(this.selectedIndex != 0){
  507. this.select(this.selectedIndex-1);
  508. }
  509. }
  510. },
  511. // private
  512. onKeyUp : function(e){
  513. if(this.editable !== false && !e.isSpecialKey()){
  514. this.lastKey = e.getKey();
  515. this.dqTask.delay(this.queryDelay);
  516. }
  517. },
  518. // private
  519. validateBlur : function(){
  520. return !this.list || !this.list.isVisible();
  521. },
  522. // private
  523. initQuery : function(){
  524. this.doQuery(this.getRawValue());
  525. },
  526. // private
  527. doForce : function(){
  528. if(this.el.dom.value.length > 0){
  529. this.el.dom.value =
  530. this.lastSelectionText === undefined ? '' : this.lastSelectionText;
  531. this.applyEmptyText();
  532. }
  533. },
  534. doQuery : function(q, forceAll){
  535. if(q === undefined || q === null){
  536. q = '';
  537. }
  538. var qe = {
  539. query: q,
  540. forceAll: forceAll,
  541. combo: this,
  542. cancel:false
  543. };
  544. if(this.fireEvent('beforequery', qe)===false || qe.cancel){
  545. return false;
  546. }
  547. q = qe.query;
  548. forceAll = qe.forceAll;
  549. if(forceAll === true || (q.length >= this.minChars)){
  550. if(this.lastQuery !== q){
  551. this.lastQuery = q;
  552. if(this.mode == 'local'){
  553. this.selectedIndex = -1;
  554. if(forceAll){
  555. this.store.clearFilter();
  556. }else{
  557. this.store.filter(this.displayField, q);
  558. }
  559. this.onLoad();
  560. }else{
  561. this.store.baseParams[this.queryParam] = q;
  562. this.store.load({
  563. params: this.getParams(q)
  564. });
  565. this.expand();
  566. }
  567. }else{
  568. this.selectedIndex = -1;
  569. this.onLoad();
  570. }
  571. }
  572. },
  573. // private
  574. getParams : function(q){
  575. var p = {};
  576. //p[this.queryParam] = q;
  577. if(this.pageSize){
  578. p.start = 0;
  579. p.limit = this.pageSize;
  580. }
  581. return p;
  582. },
  583. /**
  584. * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
  585. */
  586. collapse : function(){
  587. if(!this.isExpanded()){
  588. return;
  589. }
  590. this.list.hide();
  591. Ext.getDoc().un('mousewheel', this.collapseIf, this);
  592. Ext.getDoc().un('mousedown', this.collapseIf, this);
  593. this.fireEvent('collapse', this);
  594. },
  595. // private
  596. collapseIf : function(e){
  597. if(!e.within(this.wrap) && !e.within(this.list)){
  598. this.collapse();
  599. }
  600. },
  601. /**
  602. * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
  603. */
  604. expand : function(){
  605. if(this.isExpanded() || !this.hasFocus){
  606. return;
  607. }
  608. this.list.alignTo(this.wrap, this.listAlign);
  609. var hvalueArray=this.hiddenField.value.split(this.valueSeparator);
  610. for(var i=0;i<this.store.data.length;i++){
  611. var r = this.store.getAt(i);
  612. var newValue = r.data[this.displayField];
  613. var v=r.data[this.valueField];
  614. for(var j=0;j<hvalueArray.length;j++){
  615. if(hvalueArray[j]==v){
  616. document.getElementById("checkBox_"+newValue).className="checked";
  617. }
  618. }
  619. }
  620. this.list.show();
  621. Ext.getDoc().on('mousewheel', this.collapseIf, this);
  622. Ext.getDoc().on('mousedown', this.collapseIf, this);
  623. this.fireEvent('expand', this);
  624. },
  625. // private
  626. // Implements the default empty TriggerField.onTriggerClick function
  627. onTriggerClick : function(){
  628. if(this.disabled){
  629. return;
  630. }
  631. if(this.isExpanded()){
  632. this.collapse();
  633. this.el.focus();
  634. }else {
  635. this.onFocus({});
  636. if(this.triggerAction == 'all') {
  637. this.doQuery(this.allQuery, true);
  638. } else {
  639. this.doQuery(this.getRawValue());
  640. }
  641. this.el.focus();
  642. }
  643. }
  644. });
  645. Ext.reg('multicombo', Ext.form.MultiComboBox);
  1. <span class="hilite1">Ext</span>
  2. .form.MultiComboBox = <span class="hilite1">Ext</span>
  3. .extend(<span class="hilite1">Ext</span>
  4. .form.TriggerField, {
  5. defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
  6. listClass: '',
  7. selectedClass: 'x-combo-selected',
  8. triggerClass : 'x-form-arrow-trigger',
  9. shadow:'sides',
  10. listAlign: 'tl-bl?',
  11. maxHeight: 300,
  12. triggerAction: 'query',
  13. minChars : 4,
  14. typeAhead: false,
  15. queryDelay: 500,
  16. pageSize: 0,
  17. selectOnFocus:false,
  18. queryParam: 'query',
  19. loadingText: 'Loading...',
  20. resizable: false,
  21. handleHeight : 8,
  22. editable: true,
  23. allQuery: '',
  24. mode: 'remote',
  25. minListWidth : 70,
  26. forceSelection:false,
  27. typeAheadDelay : 250,
  28. displaySeparator:';',
  29. valueSeparator:',',
  30. lazyInit : true,
  31. initComponent : function(){
  32. <span class="hilite1">Ext</span>
  33. .form.ComboBox.superclass.initComponent.call(this);
  34. this.addEvents(
  35. 'expand',
  36. 'collapse',
  37. 'beforeselect',
  38. 'select',
  39. 'beforequery'
  40. );
  41. if(this.transform){
  42. this.allowDomMove = false;
  43. var s = <span class="hilite1">Ext</span>
  44. .getDom(this.transform);
  45. if(!this.hiddenName){
  46. this.hiddenName = s.name;
  47. }
  48. if(!this.store){
  49. this.mode = 'local';
  50. var d = [], opts = s.options;
  51. for(var i = 0, len = opts.length;i < len; i++){
  52. var o = opts[i];
  53. var value = (<span class="hilite1">Ext</span>
  54. .isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
  55. if(o.selected) {
  56. this.value = value;
  57. }
  58. d.push([value, o.text]);
  59. }
  60. this.store = new <span class="hilite1">Ext</span>
  61. .data.SimpleStore({
  62. 'id': 0,
  63. fields: ['value', 'text'],
  64. data : d
  65. });
  66. this.valueField = 'value';
  67. this.displayField = 'text';
  68. }
  69. s.name = <span class="hilite1">Ext</span>
  70. .id(); // wipe out the name in case somewhere else they have a reference
  71. if(!this.lazyRender){
  72. this.target = true;
  73. this.el = <span class="hilite1">Ext</span>
  74. .DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
  75. <span class="hilite1">Ext</span>
  76. .removeNode(s); // remove it
  77. this.render(this.el.parentNode);
  78. }else{
  79. <span class="hilite1">Ext</span>
  80. .removeNode(s); // remove it
  81. }
  82. }
  83. this.selectedIndex = -1;
  84. if(this.mode == 'local'){
  85. if(this.initialConfig.queryDelay === undefined){
  86. this.queryDelay = 10;
  87. }
  88. if(this.initialConfig.minChars === undefined){
  89. this.minChars = 0;
  90. }
  91. }
  92. },
  93. // private
  94. onRender : function(ct, position){
  95. <span class="hilite1">Ext</span>
  96. .form.ComboBox.superclass.onRender.call(this, ct, position);
  97. var disValue="";
  98. if(this.hiddenName){
  99. this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
  100. 'before', true);
  101. var hvalue=this.hiddenValue !== undefined ? this.hiddenValue :
  102. this.value !== undefined ? this.value : '';
  103. var hvalueArray=hvalue.split(this.valueSeparator);
  104. for(var i=0;i<this.store.data.length;i++){
  105. var r = this.store.getAt(i);
  106. var newValue = r.data[this.displayField];
  107. var v=r.data[this.valueField];
  108. for(var j=0;j<hvalueArray.length;j++){
  109. if(hvalueArray[j]==v){
  110. disValue+=newValue+this.displaySeparator;
  111. }
  112. }
  113. }
  114. this.hiddenField.value =this.hiddenValue !== undefined ? this.hiddenValue :
  115. this.value !== undefined ? this.value : '';
  116. this.el.dom.removeAttribute('name');
  117. }
  118. if(<span class="hilite1">Ext</span>
  119. .isGecko){
  120. this.el.dom.setAttribute('autocomplete', 'off');
  121. }
  122. if(!this.lazyInit){
  123. this.initList();
  124. }else{
  125. this.on('focus', this.initList, this, {single: true});
  126. }
  127. if(!this.editable){
  128. this.editable = true;
  129. this.setEditable(false);
  130. }
  131. this.setValue(disValue);
  132. },
  133. initList : function(){
  134. if(!this.list){
  135. var cls = 'x-combo-list';
  136. this.list = new <span class="hilite1">Ext</span>
  137. .Layer({
  138. shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
  139. });
  140. var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
  141. this.list.setWidth(lw);
  142. this.list.swallowEvent('mousewheel');
  143. this.assetHeight = 0;
  144. if(this.title){
  145. this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
  146. this.assetHeight += this.header.getHeight();
  147. }
  148. this.innerList = this.list.createChild({cls:cls+'-inner'});
  149. this.innerList.on('mouseover', this.onViewOver, this);
  150. this.innerList.on('mousemove', this.onViewMove, this);
  151. this.innerList.setWidth(lw - this.list.getFrameWidth('lr'))
  152. if(this.pageSize){
  153. this.footer = this.list.createChild({cls:cls+'-ft'});
  154. this.pageTb = new <span class="hilite1">Ext</span>
  155. .PagingToolbar({
  156. store:this.store,
  157. pageSize: this.pageSize,
  158. renderTo:this.footer
  159. });
  160. this.assetHeight += this.footer.getHeight();
  161. }
  162. if(!this.tpl){
  163. //alert(cls);
  164. //x-combo-list-item
  165. this.tpl = '<tpl for="."><div class="'+cls+'-item"><span class="unchecked" id="checkBox_{' + this.displayField + '}"+ width="20">&nbsp;&nbsp;&nbsp;&nbsp;</span>{' + this.displayField + '}</div></tpl>';
  166. }
  167. this.view = new <span class="hilite1">Ext</span>
  168. .DataView({
  169. applyTo: this.innerList,
  170. tpl: this.tpl,
  171. singleSelect: true,
  172. selectedClass: this.selectedClass,
  173. itemSelector: this.itemSelector || '.' + cls + '-item'
  174. });
  175. this.view.on('click', this.onViewClick, this);
  176. this.bindStore(this.store, true);
  177. if(this.resizable){
  178. this.resizer = new <span class="hilite1">Ext</span>
  179. .Resizable(this.list, {
  180. pinned:true, handles:'se'
  181. });
  182. this.resizer.on('resize', function(r, w, h){
  183. this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
  184. this.listWidth = w;
  185. this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
  186. this.restrictHeight();
  187. }, this);
  188. this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
  189. }
  190. }
  191. },
  192. bindStore : function(store, initial){
  193. if(this.store && !initial){
  194. this.store.un('beforeload', this.onBeforeLoad, this);
  195. this.store.un('load', this.onLoad, this);
  196. this.store.un('loadexception', this.collapse, this);
  197. if(!store){
  198. this.store = null;
  199. if(this.view){
  200. this.view.setStore(null);
  201. }
  202. }
  203. }
  204. if(store){
  205. this.store = <span class="hilite1">Ext</span>
  206. .StoreMgr.lookup(store);
  207. this.store.on('beforeload', this.onBeforeLoad, this);
  208. this.store.on('load', this.onLoad, this);
  209. this.store.on('loadexception', this.collapse, this);
  210. if(this.view){
  211. this.view.setStore(store);
  212. }
  213. }
  214. },
  215. // private
  216. initEvents : function(){
  217. <span class="hilite1">Ext</span>
  218. .form.ComboBox.superclass.initEvents.call(this);
  219. this.keyNav = new <span class="hilite1">Ext</span>
  220. .KeyNav(this.el, {
  221. "up" : function(e){
  222. this.inKeyMode = true;
  223. this.selectPrev();
  224. },
  225. "down" : function(e){
  226. if(!this.isExpanded()){
  227. this.onTriggerClick();
  228. }else{
  229. this.inKeyMode = true;
  230. this.selectNext();
  231. }
  232. },
  233. "enter" : function(e){
  234. this.onViewClick();
  235. //return true;
  236. },
  237. "esc" : function(e){
  238. this.collapse();
  239. },
  240. "tab" : function(e){
  241. this.onViewClick(false);
  242. return true;
  243. },
  244. scope : this,
  245. doRelay : function(foo, bar, hname){
  246. if(hname == 'down' || this.scope.isExpanded()){
  247. return <span class="hilite1">Ext</span>
  248. .KeyNav.prototype.doRelay.apply(this, arguments);
  249. }
  250. return true;
  251. },
  252. forceKeyDown : true
  253. });
  254. this.queryDelay = Math.max(this.queryDelay || 10,
  255. this.mode == 'local' ? 10 : 250);
  256. this.dqTask = new <span class="hilite1">Ext</span>
  257. .util.DelayedTask(this.initQuery, this);
  258. if(this.typeAhead){
  259. this.taTask = new <span class="hilite1">Ext</span>
  260. .util.DelayedTask(this.onTypeAhead, this);
  261. }
  262. if(this.editable !== false){
  263. this.el.on("keyup", this.onKeyUp, this);
  264. }
  265. if(this.forceSelection){
  266. this.on('blur', this.doForce, this);
  267. }
  268. },
  269. onDestroy : function(){
  270. if(this.view){
  271. this.view.el.removeAllListeners();
  272. this.view.el.remove();
  273. this.view.purgeListeners();
  274. }
  275. if(this.list){
  276. this.list.destroy();
  277. }
  278. this.bindStore(null);
  279. <span class="hilite1">Ext</span>
  280. .form.ComboBox.superclass.onDestroy.call(this);
  281. },
  282. // private
  283. fireKey : function(e){
  284. if(e.isNavKeyPress() && !this.list.isVisible()){
  285. this.fireEvent("specialkey", this, e);
  286. }
  287. },
  288. // private
  289. onResize: function(w, h){
  290. <span class="hilite1">Ext</span>
  291. .form.ComboBox.superclass.onResize.apply(this, arguments);
  292. if(this.list && this.listWidth === undefined){
  293. var lw = Math.max(w, this.minListWidth);
  294. this.list.setWidth(lw);
  295. this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
  296. }
  297. },
  298. // private
  299. onDisable: function(){
  300. <span class="hilite1">Ext</span>
  301. .form.ComboBox.superclass.onDisable.apply(this, arguments);
  302. if(this.hiddenField){
  303. this.hiddenField.disabled = this.disabled;
  304. }
  305. },
  306. setEditable : function(value){
  307. if(value == this.editable){
  308. return;
  309. }
  310. this.editable = value;
  311. if(!value){
  312. this.el.dom.setAttribute('readOnly', true);
  313. this.el.on('mousedown', this.onTriggerClick, this);
  314. this.el.addClass('x-combo-noedit');
  315. }else{
  316. this.el.dom.setAttribute('readOnly', false);
  317. this.el.un('mousedown', this.onTriggerClick, this);
  318. this.el.removeClass('x-combo-noedit');
  319. }
  320. },
  321. // private
  322. onBeforeLoad : function(){
  323. if(!this.hasFocus){
  324. return;
  325. }
  326. this.innerList.update(this.loadingText ?
  327. '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
  328. this.restrictHeight();
  329. this.selectedIndex = -1;
  330. },
  331. // private
  332. onLoad : function(){
  333. if(!this.hasFocus){
  334. return;
  335. }
  336. if(this.store.getCount() > 0){
  337. this.expand();
  338. this.restrictHeight();
  339. if(this.lastQuery == this.allQuery){
  340. if(this.editable){
  341. this.el.dom.select();
  342. }
  343. if(!this.selectByValue(this.value, true)){
  344. this.select(0, true);
  345. }
  346. }else{
  347. this.selectNext();
  348. if(this.typeAhead && this.lastKey != <span class="hilite1">Ext</span>
  349. .EventObject.BACKSPACE && this.lastKey != <span class="hilite1">Ext</span>
  350. .EventObject.DELETE){
  351. this.taTask.delay(this.typeAheadDelay);
  352. }
  353. }
  354. }else{
  355. this.onEmptyResults();
  356. }
  357. },
  358. // private
  359. onTypeAhead : function(){
  360. if(this.store.getCount() > 0){
  361. var r = this.store.getAt(0);
  362. var newValue = r.data[this.displayField];
  363. var len = newValue.length;
  364. var selStart = this.getRawValue().length;
  365. if(selStart != len){
  366. this.setRawValue(newValue);
  367. this.selectText(selStart, newValue.length);
  368. }
  369. }
  370. },
  371. // private
  372. onSelect : function(record, index){
  373. if(this.fireEvent('beforeselect', this, record, index) !== false){
  374. var r = this.store.getAt(index);
  375. var newValue = r.data[this.displayField];
  376. var check=document.getElementById("checkBox_"+newValue);
  377. if(check.className=="checked"){
  378. check.className="unchecked"
  379. }else{
  380. check.className="checked"
  381. }
  382. var value="";
  383. var hiddenValue="";
  384. for(var i=0;i<this.store.data.length;i++){
  385. var r = this.store.getAt(i);
  386. newValue = r.data[this.displayField];
  387. check=document.getElementById("checkBox_"+newValue);
  388. if(check.className=="checked"){
  389. value+= r.data[this.displayField]+this.displaySeparator;
  390. hiddenValue+= r.data[this.valueField]+this.valueSeparator;
  391. }
  392. }
  393. if(value.length>1){
  394. value=value.substring(0,value.length-this.displaySeparator.length);
  395. }
  396. if(hiddenValue.length>1){
  397. hiddenValue=hiddenValue.substring(0,value.length-this.valueSeparator.length);
  398. }
  399. this.setValue(value);
  400. this.hiddenField.value=hiddenValue;
  401. this.fireEvent('select', this, record, index);
  402. }
  403. },
  404. getValue : function(){
  405. if(this.valueField){
  406. return typeof this.value != 'undefined' ? this.value : '';
  407. }else{
  408. return <span class="hilite1">Ext</span>
  409. .form.ComboBox.superclass.getValue.call(this);
  410. }
  411. },
  412. /**
  413. * Clears any text/value currently set in the field
  414. */
  415. clearValue : function(){
  416. if(this.hiddenField){
  417. this.hiddenField.value = '';
  418. }
  419. this.setRawValue('');
  420. this.lastSelectionText = '';
  421. this.applyEmptyText();
  422. },
  423. setValue : function(v){
  424. var text = v;
  425. if(this.valueField){
  426. var r = this.findRecord(this.valueField, v);
  427. if(r){
  428. text = r.data[this.displayField];
  429. }else if(this.valueNotFoundText !== undefined){
  430. text = this.valueNotFoundText;
  431. }
  432. }
  433. this.lastSelectionText = text;
  434. <span class="hilite1">Ext</span>
  435. .form.ComboBox.superclass.setValue.call(this, text);
  436. this.value = v;
  437. },
  438. // private
  439. findRecord : function(prop, value){
  440. var record;
  441. if(this.store.getCount() > 0){
  442. this.store.each(function(r){
  443. if(r.data[prop] == value){
  444. record = r;
  445. return false;
  446. }
  447. });
  448. }
  449. return record;
  450. },
  451. // private
  452. onViewMove : function(e, t){
  453. this.inKeyMode = false;
  454. },
  455. // private
  456. onViewOver : function(e, t){
  457. if(this.inKeyMode){ // prevent key nav and mouse over conflicts
  458. return;
  459. }
  460. var item = this.view.findItemFromChild(t);
  461. if(item){
  462. var index = this.view.indexOf(item);
  463. this.select(index, false);
  464. }
  465. },
  466. // private
  467. onViewClick : function(doFocus){
  468. var index = this.view.getSelectedIndexes()[0];
  469. var r = this.store.getAt(index);
  470. if(r){
  471. this.onSelect(r, index);
  472. }
  473. if(doFocus !== false){
  474. this.el.focus();
  475. }
  476. },
  477. // private
  478. restrictHeight : function(){
  479. this.innerList.dom.style.height = '';
  480. var inner = this.innerList.dom;
  481. var fw = this.list.getFrameWidth('tb');
  482. var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
  483. this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
  484. this.list.beginUpdate();
  485. this.list.setHeight(this.innerList.getHeight()+fw+(this.resizable?this.handleHeight:0)+this.assetHeight);
  486. this.list.alignTo(this.el, this.listAlign);
  487. this.list.endUpdate();
  488. },
  489. // private
  490. onEmptyResults : function(){
  491. this.collapse();
  492. },
  493. /**
  494. * Returns true if the dropdown list is expanded, else false.
  495. */
  496. isExpanded : function(){
  497. return this.list && this.list.isVisible();
  498. },
  499. selectByValue : function(v, scrollIntoView){
  500. if(v !== undefined && v !== null){
  501. var r = this.findRecord(this.valueField || this.displayField, v);
  502. if(r){
  503. this.select(this.store.indexOf(r), scrollIntoView);
  504. return true;
  505. }
  506. }
  507. return false;
  508. },
  509. select : function(index, scrollIntoView){
  510. this.selectedIndex = index;
  511. this.view.select(index);
  512. if(scrollIntoView !== false){
  513. var el = this.view.getNode(index);
  514. if(el){
  515. this.innerList.scrollChildIntoView(el, false);
  516. }
  517. }
  518. },
  519. // private
  520. selectNext : function(){
  521. var ct = this.store.getCount();
  522. if(ct > 0){
  523. if(this.selectedIndex == -1){
  524. this.select(0);
  525. }else if(this.selectedIndex < ct-1){
  526. this.select(this.selectedIndex+1);
  527. }
  528. }
  529. },
  530. // private
  531. selectPrev : function(){
  532. var ct = this.store.getCount();
  533. if(ct > 0){
  534. if(this.selectedIndex == -1){
  535. this.select(0);
  536. }else if(this.selectedIndex != 0){
  537. this.select(this.selectedIndex-1);
  538. }
  539. }
  540. },
  541. // private
  542. onKeyUp : function(e){
  543. if(this.editable !== false && !e.isSpecialKey()){
  544. this.lastKey = e.getKey();
  545. this.dqTask.delay(this.queryDelay);
  546. }
  547. },
  548. // private
  549. validateBlur : function(){
  550. return !this.list || !this.list.isVisible();
  551. },
  552. // private
  553. initQuery : function(){
  554. this.doQuery(this.getRawValue());
  555. },
  556. // private
  557. doForce : function(){
  558. if(this.el.dom.value.length > 0){
  559. this.el.dom.value =
  560. this.lastSelectionText === undefined ? '' : this.lastSelectionText;
  561. this.applyEmptyText();
  562. }
  563. },
  564. doQuery : function(q, forceAll){
  565. if(q === undefined || q === null){
  566. q = '';
  567. }
  568. var qe = {
  569. query: q,
  570. forceAll: forceAll,
  571. combo: this,
  572. cancel:false
  573. };
  574. if(this.fireEvent('beforequery', qe)===false || qe.cancel){
  575. return false;
  576. }
  577. q = qe.query;
  578. forceAll = qe.forceAll;
  579. if(forceAll === true || (q.length >= this.minChars)){
  580. if(this.lastQuery !== q){
  581. this.lastQuery = q;
  582. if(this.mode == 'local'){
  583. this.selectedIndex = -1;
  584. if(forceAll){
  585. this.store.clearFilter();
  586. }else{
  587. this.store.filter(this.displayField, q);
  588. }
  589. this.onLoad();
  590. }else{
  591. this.store.baseParams[this.queryParam] = q;
  592. this.store.load({
  593. params: this.getParams(q)
  594. });
  595. this.expand();
  596. }
  597. }else{
  598. this.selectedIndex = -1;
  599. this.onLoad();
  600. }
  601. }
  602. },
  603. // private
  604. getParams : function(q){
  605. var p = {};
  606. //p[this.queryParam] = q;
  607. if(this.pageSize){
  608. p.start = 0;
  609. p.limit = this.pageSize;
  610. }
  611. return p;
  612. },
  613. /**
  614. * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
  615. */
  616. collapse : function(){
  617. if(!this.isExpanded()){
  618. return;
  619. }
  620. this.list.hide();
  621. <span class="hilite1">Ext</span>
  622. .getDoc().un('mousewheel', this.collapseIf, this);
  623. <span class="hilite1">Ext</span>
  624. .getDoc().un('mousedown', this.collapseIf, this);
  625. this.fireEvent('collapse', this);
  626. },
  627. // private
  628. collapseIf : function(e){
  629. if(!e.within(this.wrap) && !e.within(this.list)){
  630. this.collapse();
  631. }
  632. },
  633. /**
  634. * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
  635. */
  636. expand : function(){
  637. if(this.isExpanded() || !this.hasFocus){
  638. return;
  639. }
  640. this.list.alignTo(this.wrap, this.listAlign);
  641. var hvalueArray=this.hiddenField.value.split(this.valueSeparator);
  642. for(var i=0;i<this.store.data.length;i++){
  643. var r = this.store.getAt(i);
  644. var newValue = r.data[this.displayField];
  645. var v=r.data[this.valueField];
  646. for(var j=0;j<hvalueArray.length;j++){
  647. if(hvalueArray[j]==v){
  648. document.getElementById("checkBox_"+newValue).className="checked";
  649. }
  650. }
  651. }
  652. this.list.show();
  653. <span class="hilite1">Ext</span>
  654. .getDoc().on('mousewheel', this.collapseIf, this);
  655. <span class="hilite1">Ext</span>
  656. .getDoc().on('mousedown', this.collapseIf, this);
  657. this.fireEvent('expand', this);
  658. },
  659. // private
  660. // Implements the default empty TriggerField.onTriggerClick function
  661. onTriggerClick : function(){
  662. if(this.disabled){
  663. return;
  664. }
  665. if(this.isExpanded()){
  666. this.collapse();
  667. this.el.focus();
  668. }else {
  669. this.onFocus({});
  670. if(this.triggerAction == 'all') {
  671. this.doQuery(this.allQuery, true);
  672. } else {
  673. this.doQuery(this.getRawValue());
  674. }
  675. this.el.focus();
  676. }
  677. }
  678. });
  679. <span class="hilite1">Ext</span>
  680. .reg('multicombo', <span class="hilite1">Ext</span>
  681. .form.MultiComboBox);

ext-all.css文件最后添加两行支持样式:

1.checked{background-image:url(../images/default/menu/checked.gif)}

2.unchecked{background-image:url(../images/default/menu/unchecked.gif)}

分享到:
评论

相关推荐

    ext下拉多选组件multicombo

    通过深入学习EXTJS的"ext下拉多选组件multicombo",开发者可以掌握如何在自己的应用中实现多选下拉功能,提升用户体验。同时,对源码的研究有助于增强EXTJS框架的理解,从而更好地进行组件的扩展和定制,满足特定...

    extjs实现下拉框多选

    最后,`multiCombox` 文件名可能指的是一个包含实现多选下拉框功能的代码或示例的文件。如果你有这个文件,可以参考其中的内容,结合上述讲解来理解和学习多选ComboBox的实现。在实践中,不断探索和调试,你将更熟练...

    低成本单发单收激光测距传感器方案详解:硬件设计、代码实现及应用案例

    内容概要:本文详细介绍了低成本单发单收激光测距传感器的一站式解决方案,涵盖硬件设计、软件实现及其应用。硬件部分基于STM32F030F4P6芯片,搭配激光发射管和APD接收模块,通过精心设计的信号调理电路确保高精度测量。软件部分展示了关键代码片段,如初始化、测距算法和ADC配置,采用改进型飞行时间法(ToF)并通过DMA优化数据处理效率。此外,文章还讨论了调试过程中遇到的问题及解决方案,如环境光干扰和PCB布局优化。最终,该方案实现了0.05-50米范围内±1.5mm的测距精度,适用于多种应用场景。 适合人群:电子爱好者、硬件工程师、嵌入式系统开发者。 使用场景及目标:① DIY爱好者可以通过本方案进行个人项目的开发;② 企业可以基于此方案进行商业产品的开发,降低成本;③ 教育机构可以用作教学案例,帮助学生理解激光测距原理和技术实现。 其他说明:文章不仅提供详细的硬件和软件设计方案,还包括BOM清单、供应商信息和调试指南,有助于快速实现和优化项目。

    基于麻雀算法优化LSTM的时间序列预测——MATLAB实现及应用

    内容概要:本文详细介绍了将麻雀算法(SSA)应用于LSTM参数优化的方法及其MATLAB实现。首先,通过生成带噪声的正弦波数据模拟真实场景的数据扰动,然后定义适应度函数用于评估LSTM模型的表现。接着,利用麻雀算法的发现者和跟随者角色进行参数优化,最终实现了比随机调参更好的预测效果。文中不仅提供了完整的代码实现,还讨论了参数设置的经验值以及一些实用技巧,如数据归一化、早停机制和并行加速等。 适合人群:对机器学习尤其是深度学习有一定了解的研究人员和技术爱好者,熟悉MATLAB编程环境。 使用场景及目标:适用于需要提高时间序列预测精度的任务,如金融数据分析、天气预报等领域。主要目标是通过引入生物启发式的优化算法来提升LSTM模型的性能。 其他说明:文中提到的麻雀算法能够显著减少人工调参的工作量,并且相比传统的网格搜索法更加高效。此外,作者还分享了一些实践经验,帮助读者更好地理解和应用这一方法。

    西门子Smart200 PLC实现高效星三角降压启动子程序及应用

    内容概要:本文详细介绍了使用西门子Smart200 PLC实现高效的星三角降压启动子程序的方法。作者分享了具体的编程技巧,包括参数化的外部配置、定时器的巧妙运用以及故障处理机制。文中展示了完整的主程序调用示例和子程序内部逻辑,强调了模块化编程的优势,使得不同电机可以轻松复用相同的子程序,极大提高了调试和维护效率。此外,作者还提到了一些常见的调试陷阱和优化建议,如避免星三角同时导通、合理设置切换时间和加入硬件互锁等。 适合人群:从事PLC编程、自动化控制领域的工程师和技术人员,尤其是那些希望提高编程效率和代码复用性的从业者。 使用场景及目标:适用于需要频繁进行电机星三角降压启动的工业应用场景,如纺织厂、水泥厂等。主要目标是通过模块化编程减少重复劳动,提升系统稳定性和响应速度。 其他说明:文章不仅提供了详细的代码示例,还分享了许多实践经验,帮助读者更好地理解和应用这些技术。

    2025中国数字营销趋势报告.pdf

    2025中国数字营销趋势报告.pdf

    威纶通MT6071iP一机多屏控制信捷PLC的技术实现与应用

    内容概要:本文详细介绍了如何利用两台威纶通MT6071iP触摸屏控制一台信捷PLC的具体步骤和技术要点。主要内容涵盖硬件连接、触摸屏设置、PLC编程、调试与优化等方面。文中不仅提供了具体的配置方法,如通讯参数设置、画面设计、宏指令处理等,还分享了许多实际操作中的经验和注意事项,如地址分配、数据同步、通讯稳定性提升等。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是那些需要实现多屏协同控制PLC系统的工作者。 使用场景及目标:适用于需要提高生产线上设备操作便捷性和监控灵活性的场合。通过一机多屏设置,可以在不同位置对同一PLC进行控制,方便现场操作和远程管理。 其他说明:文章强调了硬件连接细节、通讯参数一致性、PLC编程逻辑的重要性,并提供了一些实用技巧,如宏指令处理、心跳检测、防呆设计等,帮助读者更好地理解和实施该项目。

    2024中国上市公司数字化转型报告.pdf

    2024中国上市公司数字化转型报告.pdf

    《2024年中国物联网产业创新白皮书》

    内容概要:《2024年中国物联网产业创新白皮书》由深圳市物联网产业协会与AIoT星图研究院联合编制,汇集了全国30多个省市物联网组织的智慧。白皮书系统梳理了中国物联网产业的发展历程、现状及未来趋势,涵盖了物联网的概念、产业结构、市场规模、投融资情况、面临的问题与机遇。书中详细分析了感知层、传输层、平台层及应用层的关键技术,探讨了智慧城市、智能工业、车联网、智慧医疗等九大产业物联网应用领域,以及消费物联网的发展特征与热门单品。此外,白皮书还关注了物联网数据安全、法规遵从、人才短缺等挑战,并提出了相应的解决方案。 适用人群:物联网从业者、企业决策者、政策制定者及相关研究机构。 使用场景及目标:①帮助从业者深入了解物联网产业的现状和发展趋势;②为企业决策者提供战略规划依据;③为政策制定者提供政策支持和法规制定参考;④为研究机构提供详尽的数据和案例支持。 其他说明:白皮书不仅限于技术科普,更从宏观角度结合市场情况,多维度讨论了物联网产业生态,旨在为物联网企业、从业者找到最适合的技术应用场景,促进产业健康发展。报告还特别鸣谢了参与市场调研的企业,感谢他们提供的宝贵行业信息。由于时间和资源的限制,报告可能存在信息不充分之处,欢迎各界人士提出宝贵意见。

    汇川H5U PLC结构体编程优化工业控制系统设计与应用

    内容概要:本文详细介绍了汇川H5U PLC中采用结构体编程的优势及其具体应用场景。作者通过多个实际项目案例展示了结构体编程如何显著提高代码的整洁度、可维护性和扩展性。文中特别强调了结构体在处理大量相似设备(如气缸、阀门、伺服轴)时的作用,以及如何利用结构体简化变量管理、增强在线调试体验并减少内存消耗。此外,还讨论了一些常见的注意事项和技术细节,如结构体初始化、功能块集成、在线修改功能的应用等。 适用人群:从事工业自动化系统开发的技术人员,尤其是对PLC编程有一定经验的工程师。 使用场景及目标:适用于需要高效管理和维护复杂工业控制系统的场合,旨在帮助工程师更好地理解和掌握结构体编程技巧,从而提高工作效率和代码质量。 其他说明:文章提供了丰富的代码片段作为示例,便于读者直观地理解结构体编程的具体实现方法。同时提醒读者注意结构体初始化等问题,确保项目顺利进行。

    三相逆变器模型预测控制(MPC)的高效数学建模与快速仿真

    内容概要:本文介绍了如何利用数学建模替代传统的电气元件仿真,实现三相逆变器的模型预测控制(MPC)。主要内容包括三相桥的数学模型建立、代价函数设计、状态方程离散化以及仿真优化技巧。通过将三相桥的输出电压转换为矩阵运算,减少了计算复杂度,提高了仿真速度。代价函数不仅考虑了电流跟踪误差,还加入了开关频率惩罚项,以减少不必要的开关动作。此外,文中提供了详细的代码示例,展示了如何通过数学建模实现高效的MPC控制。 适合人群:从事电力电子控制系统设计的研究人员和技术人员,尤其是对三相逆变器及其控制算法感兴趣的读者。 使用场景及目标:适用于需要快速迭代和验证控制算法的场合,如光伏并网、电机驱动等领域。目标是提高仿真效率,优化控制性能,减少开发时间和成本。 其他说明:文中提到的技术手段能够显著提升仿真速度,但在应用时需要注意数值稳定性和参数辨识的准确性。

    MATLAB/Simulink中60W Flyback变换器的建模与仿真详解

    内容概要:本文详细介绍了如何使用MATLAB/Simulink构建并仿真一个60W的Flyback变换器模型,输入为390V直流,输出为19V/3A。主要内容涵盖主电路搭建(包括变压器参数设置、MOSFET选择)、吸收电路设计(RCD参数调整)、闭环控制系统(PID参数调节)以及动态性能测试。文中还提供了多个实用技巧,如防止变压器饱和、优化吸收电路参数、提高动态响应速度等,并指出了常见的错误及其解决方案。同时,推荐了几本相关领域的经典书籍供进一步学习。 适合人群:初学者和有一定基础的电源设计师,特别是希望深入了解Flyback变换器工作原理和技术细节的人群。 使用场景及目标:适用于需要进行中小功率电源设计的研究人员和工程师,旨在帮助他们掌握Flyback变换器的设计方法,提升仿真的准确性和可靠性。 其他说明:提供的仿真文件可以在MATLAB 2017b及以上版本运行,建议读者按照文中步骤逐步实践,以便更好地理解和应用所学知识。

    2024年中国城市低空经济发展指数报告

    内容概要:《2024年中国城市低空经济发展指数报告》由36氪研究院发布,指出低空经济作为新质生产力的代表,已成为中国经济新的增长点。报告从发展环境、资金投入、创新能力、基础支撑和发展成效五个维度构建了综合指数评价体系,评估了全国重点城市的低空经济发展状况。北京和深圳在总指数中名列前茅,分别以91.26和84.53的得分领先,展现出强大的资金投入、创新能力和基础支撑。低空经济主要涉及无人机、eVTOL(电动垂直起降飞行器)和直升机等产品,广泛应用于农业、物流、交通、应急救援等领域。政策支持、市场需求和技术进步共同推动了低空经济的快速发展,预计到2026年市场规模将突破万亿元。 适用人群:对低空经济发展感兴趣的政策制定者、投资者、企业和研究人员。 使用场景及目标:①了解低空经济的定义、分类和发展驱动力;②掌握低空经济的主要应用场景和市场规模预测;③评估各城市在低空经济发展中的表现和潜力;④为政策制定、投资决策和企业发展提供参考依据。 其他说明:报告强调了政策监管、产业生态建设和区域融合错位的重要性,提出了加强法律法规建设、人才储备和基础设施建设等建议。低空经济正加速向网络化、智能化、规模化和集聚化方向发展,各地应找准自身比较优势,实现差异化发展。

    汇川H5U PLC程序框架:基于ETHERCAT总线的高效自动化控制系统

    内容概要:本文深入探讨了汇川H5U PLC程序框架,尤其是其在ETHERCAT总线控制方面的应用。该框架提供了完整的气缸控制、轴控制等功能模块,涵盖从初始化到故障处理的全过程。文中详细介绍了气缸控制的梯形图逻辑、轴控制的具体指令及其状态机设计,并展示了触摸屏与PLC变量的绑定方法。此外,还提到了三套针对不同应用场景的程序样例,包括单机设备、流水线联动和柔性生产版本。整体而言,该框架以其条理分明的代码结构和丰富的功能模块,成为自动化控制领域的有力工具。 适合人群:从事工业自动化控制系统的工程师和技术人员,特别是初学者和希望深入了解汇川H5U PLC及ETHERCAT总线控制的专业人士。 使用场景及目标:适用于需要高效、稳定的多轴运动控制和人机交互的自动化项目。主要目标是帮助用户快速掌握汇川H5U PLC的编程技巧,提高项目的开发效率和可靠性。 其他说明:文章强调了框架的实用性、易用性和详细的文档支持,使得即使是新手也能轻松上手并应用于实际项目中。

    目标: 通过统计文本中各个词汇的出现频率,找出文本中的关键词,帮助我们了解文本的核心内容 方案: 统计词频:计算每个词汇在文本中的出现次数 常用方法有TF(词频)和TF-IDF(词频-逆文档频率)

    https://blog.csdn.net/qianqianaao/article/details/147515496?fromshare=blogdetail&sharetype=blogdetail&sharerId=147515496&sharerefer=PC&sharesource=qianqianaao&sharefrom=from_link python小项目

    基于Cruise和Simulink的增程式混合动力汽车整车仿真模型构建与优化

    内容概要:本文详细介绍了如何利用Cruise和Simulink平台进行增程式混合动力汽车的整车仿真模型构建。主要内容涵盖增程器、电池、驱动电机等关键部件的物理参数设置,尤其是发电机和驱动电机效率MAP图的精确调整。文中强调了控制策略的重要性,将其分为驾驶模式选择、扭矩分配、SOC平衡三个子系统,并讨论了模式切换逻辑、再生制动策略以及DLL联合仿真的难点和技术细节。此外,作者分享了许多实用的经验和技巧,如使用二维插值提高增程器工作效率、设置合理的滞回区避免模式震荡、通过环形缓冲区解决时钟同步问题等。 适合人群:从事新能源汽车研究的技术人员、高校相关专业师生、对混合动力汽车仿真感兴趣的工程师。 使用场景及目标:帮助读者掌握增程式混合动力汽车仿真模型的搭建方法,提高仿真的准确性,优化控制策略,减少开发周期和成本。 其他说明:文章提供了大量实战经验和调试技巧,有助于解决实际工作中常见的问题,如模式切换不稳定、DLL编译错误、制动能量回收不合理等。同时,还分享了一些提高仿真效率的小窍门,如使用Fast Restart功能、避免内存泄漏等。

    威纶通触摸屏编程:基于宏指令的贪吃蛇游戏逻辑解析及应用

    内容概要:本文详细介绍了威纶通触摸屏上利用EBpro软件和宏指令实现的经典贪吃蛇游戏。文中不仅剖析了游戏的核心逻辑,如蛇的移动、碰撞检测、方向控制以及食物生成算法,还探讨了宏指令在触摸屏编程中的具体应用。通过这个模板,读者可以深入了解宏指令的工作机制及其在工业触摸屏编程中的优势。 适合人群:对嵌入式系统、人机界面(HMI)编程感兴趣的开发者和技术爱好者。 使用场景及目标:① 学习如何在威纶通触摸屏上使用宏指令进行编程;② 掌握贪吃蛇游戏的基本逻辑和实现方法;③ 提升对工业触摸屏编程的理解,尤其是宏指令的应用技巧。 其他说明:文章提供了详细的代码片段和注释,帮助读者更好地理解和修改代码。同时,文中提到的一些优化建议(如防止180度急转弯、改进随机数生成等)有助于提高游戏性能和用户体验。

    基于MATLAB的SMA优化GRNN进行时间序列预测建模

    内容概要:本文详细介绍了如何利用黏菌优化算法(SMA)优化广义回归神经网络(GRNN)来进行时间序列的拟合预测建模。首先解释了SMA和GRNN的基本原理,接着提供了完整的MATLAB代码实现,包括数据加载与划分、SMA参数设置、SMA主循环、模型构建与预测、绘图与指标计算等步骤。文中不仅给出了详细的代码注释,还分享了一些实用的经验技巧,如数据处理方法、参数选择建议等。此外,通过具体的案例展示了该方法的有效性和优越性。 适合人群:对时间序列预测感兴趣的科研人员、学生以及有一定编程基础的数据分析师。 使用场景及目标:适用于需要高精度时间序列预测的应用场景,如金融、能源等领域。主要目标是提高预测精度,减少预测误差,提供可靠的预测结果。 其他说明:本文提供的代码可以直接应用于实际项目中,只需替换相应数据即可。同时,文中提到的一些经验和技巧可以帮助使用者更好地理解和应用该方法。

    C++数据结构与算法分析解题手册

    本书是《Data Structures and Algorithm Analysis in C++》第三版的解答手册,包含了该教科书中许多练习题的答案。这些答案反映了第三版第一次印刷时书籍的状态。特别排除了一般编程问题和任何解决方案在章节末尾有参考文献的问题。解决方案在完整性程度上有所不同;通常,细节留给读者。存在的少量代码段落应该是伪-C++代码,而不是完全完美的代码。本书适合已经学习过《Data Structures and Algorithm Analysis in C++》的学生或读者使用,作为理解和掌握数据结构与算法分析的辅助材料。

    网络安全-masscan-报告转换-xls格式分析用途-1745569541.zip

    网络安全_masscan_报告转换_xls格式分析用途_1745569541.zip

Global site tag (gtag.js) - Google Analytics