
class MultiSelectDiv{
constructor(div,selectCallback,renameCallback){
this.div=div;
this.div.tabIndex=0;
this.selectCallback=selectCallback;
this.renameCallback=renameCallback;
this.lastDivClicked=null;
this.keydownHandler=(e)=>this.keyDown(e);
this.div.addEventListener('keydown',this.keydownHandler);
}
cleanup(){
this.div.removeEventListener('keydown',this.keydownHandler);
}
addOption(name,value){
let div=document.createElement('div');
this.div.appendChild(div);
div.dataset.value=value;
div.onclick=(event)=>{this.optionClicked(event)};
let span=document.createElement('span');
div.appendChild(span);
span.textContent=name;
if(this.renameCallback){
div.ondblclick=(event)=>this.doubleClick(div);
}
return this.div.querySelectorAll('div').length-1;
}
doubleClick(div){
let span=div.querySelector('span');
let r=span.getBoundingClientRect();
let txt=AddElement(document.body,'input','z-index:1;box-sizing:border-box;position:absolute;padding:0;left:'+r.left+'px;top:'+r.top+'px;width:'+(r.right-r.left)+'px;height:'+(r.bottom-r.top)+'px;');
txt.type='text';
txt.value=span.textContent;
txt.select();
txt.focus();
txt.onblur=()=>{
if(txt.value.length>0){
span.textContent=txt.value;
this.renameCallback(txt.value,div.dataset.value);
}
txt.remove();
};
txt.onkeydown=(e)=>{
if(e.key=='Enter' || e.keyCode==13){
txt.blur();
}else if(e.key=='Escape' || e.keyCode==27){
txt.value='';
txt.blur();
}
};
}
setOption(index,name,value){
let divs=this.div.querySelectorAll('div');
if(index>-1 && index<divs.length){
let span=divs[index].querySelector('span');
span.textContent=name;
divs[index].dataset.value=value;
}
}
setOrder(newVals){
let divs=this.div.querySelectorAll('div');
for(let i=0;i<newVals.length;i++){
for(let div of divs){
if(div.dataset.value==newVals[i]){
this.div.appendChild(div);
break;
}
}
}
}
removeSelectedOptions(){
let divs=this.div.querySelectorAll('div');
for(let div of divs){
if(div.dataset.selected){
if(div==this.lastDivClicked)this.lastDivClicked=null;
div.remove();
}
}
}
selectValue(value){
let divs=this.div.querySelectorAll('div');
for(let div of divs)div.dataset.selected='';
this.lastDivClicked=null;
for(let div of divs){
if(div.dataset.value==value){
this.lastDivClicked=div;
div.dataset.selected='true';
break;
}
}
}
selectValues(values){
let divs=this.div.querySelectorAll('div');
for(let div of divs)div.dataset.selected='';
this.lastDivClicked=null;
for(let div of divs){
if(values.includes(parseInt(div.dataset.value))){
this.lastDivClicked=div;
div.dataset.selected='true';
}
}
}
indexFromValue(value){
let divs=this.div.querySelectorAll('div');
for(let i=0;i<divs.length;i++)if(divs[i].dataset.value==value)return i;
return -1;
}
selectIndex(index){
let divs=this.div.querySelectorAll('div');
for(let div of divs)div.dataset.selected='';
this.lastDivClicked=null;
if(index>-1 && index<divs.length){
this.lastDivClicked=divs[index];
divs[index].dataset.selected='true';
}
}
selectedIndex(){
let divs=this.div.querySelectorAll('div');
for(let i=0;i<divs.length;i++)if(divs[i].dataset.selected)return i;
return -1;
}
selectedCount(){
let divs=this.div.querySelectorAll('div');
let count=0;
for(let div of divs)if(div.dataset.selected)count++;
return count;
}
options(){
let divs=this.div.querySelectorAll('div');
let arr=[];
for(let div of divs){
let span=div.querySelector('span');
arr.push({name:span.textContent,value:div.dataset.value});
}
return arr;
}
selectedOptions(){
let divs=this.div.querySelectorAll('div');
let arr=[];
for(let div of divs){
if(div.dataset.selected){
let span=div.querySelector('span');
arr.push({name:span.textContent,value:div.dataset.value});
}
}
return arr;
}
selectedValue(){
let divs=this.div.querySelectorAll('div');
for(let div of divs)if(div.dataset.selected)return div.dataset.value;
return '';
}
keyDown(event){
let divs=this.div.querySelectorAll('div');
let rect=this.div.getBoundingClientRect();
if(rect.width<1 || rect.height<1 || !divs.length)return;
let oldIndex=this.lastDivClicked?Array.from(divs).indexOf(this.lastDivClicked):-1;
switch(event.code){
case 'ArrowUp':
if(oldIndex===-1)this.lastDivClicked=divs[0];
else if(oldIndex>0)this.lastDivClicked=divs[oldIndex-1];
event.preventDefault();
break;
case 'ArrowDown':
if(oldIndex===-1)this.lastDivClicked=divs[divs.length-1];
if(oldIndex<divs.length-1)this.lastDivClicked=divs[oldIndex+1];
event.preventDefault();
break;
}
let newIndex=this.lastDivClicked?Array.from(divs).indexOf(this.lastDivClicked):-1;
if(newIndex!==oldIndex){
if(event.shiftKey && oldIndex!==-1){
let startIdx=Math.min(oldIndex,newIndex);
let endIdx=Math.max(oldIndex,newIndex);
for(let i=0;i<divs.length;i++)if(i>=startIdx && i<=endIdx)divs[i].dataset.selected='true';
}else{
for(let div of divs)div.dataset.selected='';
if(this.lastDivClicked)this.lastDivClicked.dataset.selected='true';
}
if(this.lastDivClicked)this.lastDivClicked.scrollIntoView({block:'nearest'});
this.selectCallback();
}
}
selectedCommaSeparatedValues(){
let divs=this.div.querySelectorAll('div');
let s='';
for(let div of divs)if(div.dataset.selected)s+=(s?',':'')+div.dataset.value;
return s;
}
setStatusForValue(value,html,tooltip){
let divs=this.div.querySelectorAll('div');
for(let div of divs){
if(div.dataset.value==value){
let span=div.querySelectorAll('span')[1];
if(html){
if(!span){
span=document.createElement('span');
div.appendChild(span);
}
span.innerHTML=html;
span.title=tooltip;
}else{
if(span)span.remove();
}
break;
}
}
}
removeAllStatus(){
let divs=this.div.querySelectorAll('div');
for(let div of divs){
let span=div.querySelectorAll('span')[1];
if(span)span.remove();
}
}
optionClicked(event){
let clickedDiv=event.target.closest('div');
if(!clickedDiv)return;
let state=this.selectionState();
if(event.metaKey){
clickedDiv.dataset.selected=clickedDiv.dataset.selected?'':'true';
this.lastDivClicked=clickedDiv;
}else if(event.shiftKey && this.lastDivClicked && clickedDiv!=this.lastDivClicked){
let divs=this.div.querySelectorAll('div');
let f=false;
for(let div of divs){
if(f){
div.dataset.selected='true';
if(div==this.lastDivClicked || div==clickedDiv)f=false;
}else{
if(div==this.lastDivClicked || div==clickedDiv){div.dataset.selected='true';f=true;}
else div.dataset.selected='';
}
}
}else{
let divs=this.div.querySelectorAll('div');
for(let div of divs)div.dataset.selected='';
clickedDiv.dataset.selected='true';
this.lastDivClicked=clickedDiv;
}
if(this.selectionState()!=state)this.selectCallback();
}
selectionState(){
let state='';
let divs=this.div.querySelectorAll('div');
for(let div of divs)state+=div.dataset.selected?'1':'0';
return state;
}
}
