/////////////////////////////////////////////////////////////////////////// // Copyright © 2014 - 2018 Esri. All Rights Reserved. // // Licensed under the Apache License Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /////////////////////////////////////////////////////////////////////////// define([ 'dojo/_base/lang', 'dojo/_base/html', 'dojo/Evented', 'dojo/on', 'dojo/dom-attr', 'dojo/_base/declare', 'dijit/_WidgetBase', 'dojo/query', 'dijit/form/ValidationTextBox', 'dijit/form/NumberTextBox', 'dijit/_TemplatedMixin', 'dijit/_WidgetsInTemplateMixin', 'dojo/text!./EditTable.html', 'jimu/utils' ], function(lang, html, Evented, on, domAttr, declare, _WidgetBase, query, ValidationTextBox, NumberTextBox, _TemplatedMixin, _WidgetsInTemplateMixin,template, jimuUtils) { return declare([_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin, Evented], { templateString: template, currentItem: null, //for radio dataList:[], codedValues: null, //optional isNumberField: true, //for validate tableType: 'unique', //for input[type=radio] postMixInProperties:function(){ this.inherited(arguments); this.CommonNls = window.jimuNls.common; this.Nls = window.jimuNls.filterBuilder; }, postCreate: function(){ this.inherited(arguments); html.addClass(this.domNode, 'jimu-filter-mutcheck-list-value-provider'); if(this.tableType === 'unique'){ this.inputType = 'radio'; }else{ this.inputType = 'checkbox'; } }, //add dblclick event to item. _onListContentDblClicked: function(event){ // console.log('dbclick...'); this.isSearch = false; var target = event.target || event.srcElement; var itemDom = jimuUtils.getAncestorDom(target, function(dom){ return html.hasClass(dom, 'item'); }, 3); if(!itemDom){ return; } if(!(html.hasClass(target, 'name') || html.hasClass(target, 'alias'))){ return; } //allow to change emptyLabel if(html.hasClass(itemDom, 'empty') && html.hasClass(target, 'name') ){ return; } if(this._dijit){//click another when one is active this.editState = 'active'; this.updateInputDivPre = this.updateInputDiv; this._dijitPre = this._dijit; }else{ this.editState = 'negative'; } var nodeText = this._getNodeText(target); var nodeData = decodeURIComponent(html.getAttr(target, 'data')); //custom var isCustom = html.hasClass(itemDom, 'custom'); this.placeHolder = (html.hasClass(target, 'name') && !this.codedValues) ? nodeData : nodeText; if(!isCustom){ this.currentLabel = (this.isNumberField && html.hasClass(target, 'name') && !this.codedValues) ? parseFloat(this.placeHolder) : this.placeHolder;//string need to be number when operator is ',' }else{ if(html.hasClass(target, 'alias') && this.placeHolder !== this.customLabel){ this.currentLabel = nodeText; }else{ this.currentLabel = NaN; } } domAttr.set(target, "innerHTML", ''); var searchHtml = ''; if(html.hasClass(target, 'name')){ // 'Search' // searchHtml = '' + this.CommonNls.search + ''; // searchHtml = ''; searchHtml = '
'; } this.updateInputDiv = html.create("div", { "class": "updateInputDiv", "innerHTML": '
' + searchHtml }, target); var inputNode = query('.inputDiv', this.updateInputDiv)[0]; this.searchBtn = query('.searchBtn', this.updateInputDiv)[0]; this.own(on(this.updateInputDiv, 'dblclick', lang.hitch(this, function(event){ // console.log('dbclick..input...'); event.stopPropagation(); event.preventDefault(); }))); var dijitOptions = { required: false, intermediateChanges: false, value: this.currentLabel }; if(this.codedValues && html.hasClass(target, 'name')){ dijitOptions.disabled = true; } if(this.isNumberField && html.hasClass(target, 'name')){ //number dijitOptions.constraints = {pattern: "#####0.##########"}; this._dijit = new NumberTextBox(dijitOptions); }else{ //string dijitOptions.trim = true; this._dijit = new ValidationTextBox(dijitOptions); } this._dijit.startup(); this._dijit.on('keydown', (function(e){ var code = e.keyCode || e.which; if (code === 13) { this._dijit.emit('blur'); } }).bind(this)); // this._dijit.on('mouseleave', (function(event){ this._dijit.on('blur', lang.hitch(this, function(){ // input 1.235.265,256, then: // _dijit._lastInputEventValue='1.235.265,256' // _dijit.displayedValue = '1235265,256' // _dijit.value = 1235265.256 if(!this._dijit){ return; } var newLabel = this._dijit.state !== 'Error'? this._dijit.displayedValue : this.currentLabel; if(this.isNumberField && html.hasClass(target, 'name') && this._dijit.state === 'Error'){ this._dijit.setValue(parseFloat(newLabel));//reset last value when dijit has error. } newLabel = jimuUtils.sanitizeHTML(newLabel); var dijitVal = this._dijit.get('value'); if(dijitVal === '' || !dijitVal){//back to its previous value('' || NaN) newLabel = this.placeHolder; }else{ if(html.hasClass(target, 'name') && (this.placeHolder === this.customValue || (this.placeHolder === 'NaN' && this._dijit.displayedValue !== ''))){//only verify by item's value var itemDom = jimuUtils.getAncestorDom(this._dijit.domNode, function(dom){ return html.hasClass(dom, 'item'); }, 4); html.removeClass(itemDom, 'custom'); this.emit("editTable_itemChanged"); } } // domAttr.set(this._dijit.domNode.parentNode, "innerHTML", newLabel); // domAttr.set(this.updateInputDiv.parentNode, "innerHTML", newLabel); this.newLabel = newLabel; // setTimeout(lang.hitch(this, this._dijitBlurTimeout), 300); setTimeout(lang.hitch(this, function(){ var newValue, displayTxt, labelTxt; if(!this.isSearch && this.editState !== 'active'){ this.currentValLabel = this._dijit.displayedValue === '' ? this.customValue : (this.isNumberField ? this._getLocalNumber(this._dijit.value) : this._dijit.value); var inputParentNode = this.updateInputDiv.parentNode; if(html.hasClass(inputParentNode, 'name') && (this.newLabel !== 'NaN' && this.newLabel !== this.customValue) && this._getNodeText(inputParentNode.nextSibling) === this.customLabel){//value triggers label only at first time. labelTxt = this.isNumberField ? this.currentValLabel : this.newLabel; html.setAttr(inputParentNode.nextSibling, 'data', encodeURIComponent(labelTxt)); this._setNodeText(inputParentNode.nextSibling, labelTxt); } newValue = html.hasClass(inputParentNode, 'name') ? (this._dijit.displayedValue === '' ? this.customValue : this._dijit.value) : this.newLabel; html.setAttr(inputParentNode, 'data', encodeURIComponent(newValue)); displayTxt = html.hasClass(inputParentNode, 'name') ? this.currentValLabel : this.newLabel; this._setNodeText(inputParentNode, displayTxt); this._dijit = null; this.isSearch = false; }else if(this.editState === 'active'){ this.currentValLabel = this._dijitPre.displayedValue === '' ? this.customValue : (this.isNumberField ? this._getLocalNumber(this._dijitPre.value): this._dijitPre.value); var inputPreParentNode = this.updateInputDivPre.parentNode; if(html.hasClass(inputPreParentNode, 'name') && (this.newLabel !== 'NaN' && this.newLabel !== this.customValue) && (this._getNodeText(inputPreParentNode.nextSibling) === this.customLabel || this._dijit.value === this.customLabel)){ //don't trigger to update label if we click value, then click its label if(html.isDescendant(this.updateInputDiv, inputPreParentNode.nextSibling) ){ // this._dijit.set('value', this._dijitPre.value); this._dijit.set('value', this.currentValLabel); }else{ labelTxt = this.isNumberField ? this.currentValLabel : this.newLabel; html.setAttr(inputPreParentNode.nextSibling, 'data', encodeURIComponent(labelTxt)); this._setNodeText(inputPreParentNode.nextSibling, labelTxt); } } newValue = html.hasClass(inputPreParentNode, 'name') ? (this._dijitPre.displayedValue === '' ? this.customValue : this._dijitPre.value) : this.newLabel; html.setAttr(inputPreParentNode, 'data', newValue); displayTxt = html.hasClass(inputPreParentNode, 'name') ? this.currentValLabel : this.newLabel; this._setNodeText(inputPreParentNode, displayTxt); this.updateInputDivPre = null; this._dijitPre = null; this.editState = 'negative'; } }), 300); // this._dijit = null; this.placeHolder = ''; })); html.setStyle(this._dijit.domNode, 'width', '100%'); // this._dijit.placeAt(target); this._dijit.placeAt(inputNode); // this._dijit.onFocus(); // this._dijit.domNode.focus(); var input = query('input', this._dijit.domNode)[1]; // if(this._dijit.get('value') === ''){ // domAttr.set(input, "placeholder", this.placeHolder); // } input.focus(); if(this.searchBtn){ this.own(on(this.searchBtn, 'click', lang.hitch(this, function(event){ if(this.isSearch){//prevent secondary clicks // console.log('repeated click'); return; } this.isSearch = true; var _target = event.target || event.srcElement; this.searchTarget = _target; this.emit("editTable_openListSelectByName", this.newLabel); event.stopPropagation(); event.preventDefault(); }))); if(this.codedValues){ this.searchBtn.click(); } } }, _getLocalNumber: function(num){ if(typeof num === 'string'){ num = parseFloat(num); } this.emit('editTable_getValLabelsArrayForNumber', true, [num]); return this.currentValLabel; }, _setNewLabel: function(value, name){ if(value === undefined && name === undefined){ if(this._dijit.displayedValue !== ''){ if(this.codedValues){ name = this._dijit.displayedValue; value = this._getCodeFromCodevalueLabel(name); }else{ value = this._dijit.value; name = value; if(this.isNumberField && this.newLabel !== this.customValue){ name = this._getLocalNumber(value); } } }else{ value = name = this.customValue; } } // this._dijit.set('value', name); // name = name ? name : this.newLabel; if(this.updateInputDiv && this.updateInputDiv.parentNode){ var nameNode = this.updateInputDiv.parentNode; if(name !== this.customValue && this._getNodeText(nameNode.nextSibling) === this.customLabel){ html.setAttr(nameNode.nextSibling, 'data', encodeURIComponent(name)); this._setNodeText(nameNode.nextSibling, name); } if(!this.codedValues){ value = value ? value : decodeURIComponent(html.getAttr(nameNode, 'data')); } html.setAttr(nameNode, 'data', encodeURIComponent(value)); var itemDom = nameNode.parentNode; if(name !== this.customValue){ html.removeClass(itemDom, 'custom'); } this._setNodeText(nameNode, name); } this.updateInputDiv = null; this._dijit = null; }, // _onSearchClicked: function(){ // this.emit("editTable_openListSelectByName", 'table'); // }, _onListContentClicked: function(event){ var target = event.target || event.srcElement; var itemDom = jimuUtils.getAncestorDom(target, function(dom){ return html.hasClass(dom, 'item'); }, 3); if(!itemDom){ return; } if(html.hasClass(target, 'checkboxEmpty')){ if(html.hasClass(target, 'checked')){ html.removeClass(target, 'checked'); }else{ html.addClass(target, 'checked'); } }else if(html.hasClass(target, this.inputType)){ if(this.inputType === 'radio' && this.currentItem === true){ this.currentItem = this.getCurrentItem(); } if(html.hasClass(target, 'checked')){ if(this.inputType !== 'radio'){ html.removeClass(target, 'checked'); }else if(!html.hasClass(this.currentItem, 'checked')){ //can't unchecked current radio html.removeClass(target, 'checked'); } }else{ if(this.inputType === 'radio' && this.currentItem){ html.removeClass(this.currentItem, 'checked'); } html.addClass(target, 'checked'); this.currentItem = target; } }else if(html.hasClass(target, 'action')){ // if(html.hasClass(target, 'enabled')){ // html.removeClass(target, 'enabled'); // html.addClass(target, 'disabled'); // }else if(html.hasClass(target, 'disabled')){ // html.removeClass(target, 'disabled'); // html.addClass(target, 'enabled'); // }else if(html.hasClass(target, 'up')){ if(itemDom.previousElementSibling){ html.place(itemDom, itemDom.previousElementSibling, 'before'); } }else if(html.hasClass(target, 'down')){ if(itemDom.nextElementSibling){ html.place(itemDom, itemDom.nextElementSibling, 'after'); } }else if(html.hasClass(target, 'delete')){ html.destroy(itemDom); this.emit('editTable_itemChanged'); } } }, _getLabelFromCodevalue: function(codevalue){ var label = codevalue; for(var key = 0; key < this.codedValues.length; key ++){ var item = this.codedValues[key]; if(item.value === codevalue){ label = item.label; break; } } return label; }, _getCodeFromCodevalueLabel: function(label){ var codevalue = label; for(var key = 0; key < this.codedValues.length; key ++){ var item = this.codedValues[key]; if(item.label === label){ codevalue = item.value; break; } } return codevalue; }, _createEmptyTarget: function(dataList){ var name = this.emptyStr; var label = this.emptyLabel ? this.emptyLabel : name; var checkedClass = ' checked'; for(var key = 0; key < dataList.length; key ++){ if(dataList[key].isChecked){ checkedClass = ''; break; } } if(checkedClass === ' checked'){ this.currentItem = true; } var dataAttr = "data=\"" + encodeURIComponent(name) + "\""; var enableClass = ''; var enableTitle = this.Nls.emptyValueTips; if(dataList.length === 0 || this.enableEmpty){ enableClass = ' checked'; } var target = html.create("div", { "class": 'item empty', "innerHTML": '
' + name + '
' + '
' + label + '
' + '
' + '
' }, this.listContent); return target; }, _createTarget: function(name, nameLabel, label, checkedClass, isCustom){ var itemClass = 'item'; if(isCustom){ name = nameLabel = this.customValue; label = this.customLabel; itemClass = 'item custom'; } name = (name || name === 0) ? name : ""; //name could be 0 when it's a numberical field. nameLabel = nameLabel || ""; label = label ? label : name; checkedClass = checkedClass ? checkedClass : ''; //save value to nameDom include codedvalue var value = name, dataAttr = ''; if((this.codedValues || this.isNumberField) && name !== this.Nls.addValuePlaceHolder){ value = this.codedValues ? this._getLabelFromCodevalue(name) : nameLabel; } var dataValue = this.isNumberField ? name : encodeURIComponent(name);//string maybe has ',"" dataAttr = "data=\"" + dataValue + "\""; var target = html.create("div", { "class": itemClass, "innerHTML": '
' + value + '
' + '
' + label + '
' + '
' + '
' + '
' + '
' + '
' + '
' }, this.listContent); return target; }, _destroyTarget: function(name){ var labels = query('.item .name', this.listContent); for(var key = 0; key < labels.length; key++){ var label = labels[key]; var labelTxt = domAttr.get(this._dijit.domNode.parentNode, "innerHTML"); if(labelTxt === name){ html.destroy(label.parentNode); break; } } }, getCurrentItem: function(){ var items = query('.item .radio', this.listContent); for(var key = 0; key < items.length; key ++){ var item = items[key]; if(html.hasClass(item,'checked')){ return item; } } return null; }, _getEmptyLabel: function(){ var labelDom = query('.label.alias', this.listContent.firstChild)[0]; var label = this._getNodeText(labelDom); if(labelDom.children.length){//edit state label = this._dijit.state === 'Error' ? decodeURIComponent(html.getAttr(labelDom, 'data')) : this._dijit.value; } label = jimuUtils.sanitizeHTML(label); return label; }, _getEmptyStatus: function(){ // return query('.enabled', this.listContent.firstChild).length; var emptyDom = query('.checkboxEmpty', this.listContent.firstChild)[0]; return html.hasClass(emptyDom, 'checked') ? true : false; }, _getNodeText: function(target){ return target.textContent || target.innerText || ''; }, _setNodeText: function(target, label){ target.innerHTML = ' '; //for inputDom tree if(target.textContent){ target.textContent = label; }else{ target.innerText = label; } }, getListValues: function(){ this.listItemsArray = [];//['a','b','c']; this.listValuesArray = []; var items = query('.item .name',this.listContent); var firstKey = this.inputType === 'radio' ? 1 : 0; for(var key = firstKey; key < items.length; key ++){ var item = items[key]; var parentDom = jimuUtils.getAncestorDom(item, function(dom){ return html.hasClass(dom, 'item'); }, 3); if(html.hasClass(parentDom, 'custom')){//delete item if value does not update continue; } var itemVal = this._getNodeText(item); var itemData = decodeURIComponent(html.getAttr(item, 'data')); if(this.isNumberField || this.codedValues){ itemVal = itemData; } if(item.children.length){//edit state itemVal = this._dijit.state === 'Error' ? itemData : this._dijit.value; if(this.codedValues){ var code = this._getCodeFromCodevalueLabel(itemVal); itemVal = code !== undefined ? code : itemData; } } itemVal = this.isNumberField? parseFloat(itemVal): jimuUtils.sanitizeHTML(itemVal); var alias = this._getNodeText(item.nextSibling); if(alias === this.customLabel){//when value exists and label is undefined yet alias = itemVal.toString(); if(this.isNumberField){ alias = this._getLocalNumber(alias); } } if(item.nextSibling.children.length){//edit state alias = this._dijit.state === 'Error' ? decodeURIComponent(html.getAttr(item.nextSibling, 'data')) : this._dijit.value; } alias = jimuUtils.sanitizeHTML(alias); var itemObj = { value: itemVal, alias: alias, isChecked: false }; this.listItemsArray.push(itemObj); this.listValuesArray.push(itemVal); if(html.hasClass(item.nextSibling.nextSibling, 'checked')){ itemObj.isChecked = true; } } var result = { list: this.listItemsArray, valueList: this.listValuesArray //for multiple select to verify if cbxItem should be checked }; if(this.inputType === 'radio'){ result.emptyLabel = this._getEmptyLabel(); result.enableEmpty = this._getEmptyStatus();//save this to config to keep old version } return result; }, setListValues: function(dataList, labelsArray){ domAttr.set(this.listContent, "innerHTML", ''); if(this.inputType === 'radio'){ // only radio has empty target this._createEmptyTarget(dataList); } for(var key = 0; key < dataList.length; key ++){ var data = dataList[key]; var checkedClass = ''; if(data.isChecked){ checkedClass = ' checked'; this.currentItem = true; } var valLabel = labelsArray ? labelsArray[key].label : data.value; this._createTarget(data.value, valLabel, data.alias, checkedClass); } }, _initTable: function(){ }, getDijits: function(){ return [this.mutiValuesSelect]; }, destroy:function(){ this.inherited(arguments); } }); });