0
0
mirror of https://github.com/marcrobledo/savegame-editors.git synced 2025-04-28 09:05:10 +00:00

Merge pull request #394 from xiyuesaves/master

TOTK: optimize item selection feature
This commit is contained in:
Marc Robledo 2023-08-17 20:28:58 +02:00 committed by GitHub
commit 30831df258
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 348 additions and 34 deletions

View File

@ -202,6 +202,26 @@ Pouch.updateItemIcon=function(item){
else
item._htmlIcon.src=ICON_PATH+item.category+'/'+item.id+'.png';
};
Pouch.getItemIcon = function (item) {
if (item.id === "Parasail") {
var parasailPattern = typeof SavegameEditor.parasailPattern.value === "string" ? SavegameEditor.parasailPattern.value : hashReverse(SavegameEditor.parasailPattern.value);
if (parasailPattern !== "Default") {
return ICON_PATH + item.category + "/" + item.id + "_" + parasailPattern + ".png";
} else {
return ICON_PATH + item.category + "/" + item.id + ".png";
}
} else if (item.category === "armors") {
if (item.dyeColor === hash("None")) {
return ICON_PATH + item.category + "/" + item.getBaseId() + ".png";
} else {
return ICON_PATH + item.category + "/dye/" + item.getBaseId() + "_" + hashReverse(item.dyeColor) + ".png";
}
} else if (item.category === "food" && item.id === "Item_Cook_C_17" && Item.VALID_ELIXIR_EFFECTS.indexOf(hashReverse(item.effect)) !== -1) {
return ICON_PATH + item.category + "/Item_Cook_C_17_" + hashReverse(item.effect) + ".png";
} else {
return ICON_PATH + item.category + "/" + item.id + ".png";
}
},
Pouch.updateItemRow=function(item){
if(!item._htmlRow){
//create if item row does not exist

View File

@ -235,7 +235,7 @@ tr:last-child{border-bottom:none}
.border-white{border-color:white}
.border-light-gray{border-color:#d8d8d8}
.border-mid-gray{border-color:#909090}
.border-dark-gray{border-color:#48484}
.border-dark-gray{border-color:#484848}
.border-red{border-color:#e74c3c}
.border-orange{border-color:#f39c12}
.border-blue{border-color:#3498db}
@ -953,3 +953,133 @@ label.clickable:has(> input[type=radio]:checked){
.tooltip.position-horizontal.align-top .arrow{top:3px}
.tooltip.position-horizontal.align-center .arrow{top:50%;margin-top:-5px}
.tooltip.position-horizontal.align-bottom .arrow{bottom:3px}
.disable-pointer{
pointer-events: none;
}
.editItem{
display: inline-block;
position: relative;
z-index: 90;
}
.editItem,
.editItem .search-input,
.editItem .search-filter,
.editItem .search-filter *{
pointer-events: auto;
}
.editItem .search-filter{
padding: 8px 0 8px 8px;
width: 225px;
max-height: 412px;
min-height: 62px;
position: absolute;
top: 46px;
left: 0px;
background-color: #121e1a;
border-radius: 4px;
box-shadow: 0 10px 20px rgba(0, 0, 0, 0.5);
overflow: auto;
box-sizing: border-box;
}
.editItem .search-filter:empty::before{
content: "no data";
display: block;
width: 100%;
height: 46px;
line-height: 46px;
text-align: center;
color: rgba(255, 255, 255, 0.5);
font-size: 16px;
font-style: italic;
}
.editItem .search-filter::-webkit-scrollbar{
width:8px;
height:8px;
}
.editItem .search-filter::-webkit-scrollbar-track{
background: #121e1a;
border-radius:0 4px 4px 0;
}
.editItem .search-filter::-webkit-scrollbar-thumb{
background: #21362f;
border-radius:4px;
}
.editItem .search-filter .option{
width: 100%;
height: 46px;
display: flex;
justify-content: flex-start;
align-items: center;
box-sizing: border-box;
padding: 0px 4px;
transition: 300ms;
border-radius: 4px;
margin-bottom: 4px;
}
.editItem .search-filter .option:last-child{
margin-bottom: 0;
}
/* .editItem .search-filter .option:hover{
background-color: rgba(255, 255, 255, .15);
} */
.editItem .search-filter .option.active{
background-color: rgba(255, 255, 255, .15);
}
.editItem .search-filter .option .item-icon{
width: 40px;
height: 40px;
margin-right: 10px;
pointer-events: none;
}
.editItem .search-filter .option .item-name{
font-size: 15px;
color: #ffffff;
overflow : hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
pointer-events: none;
}
.editItem .search-filter .option .item-name:hover{
text-decoration: none;
}
.editItem .search-input{
width: 225px;
height: 36px;
background-color: #111111;
border: solid 1px #444444;
border-radius: 4px;
font-size: 15px;
outline: none;
color: #ffffff;
text-indent: 8px;
box-sizing: border-box;
transition: 300ms;
}
.editItem .search-input::placeholder{
font-size: 15px;
color: rgba(255, 255, 255, 0.8);
}
.editItem .search-input:hover{
border: solid 1px #666666;
}
.edit-item-mask{
position: fixed;
z-index: 80;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: 300ms;
opacity: 0;
pointer-events: none;
}
.edit-item-mask.show-mask{
pointer-events: auto;
opacity: 1;
}

View File

@ -5,6 +5,7 @@
*/
var currentEditingItem;
var inputFilter = "";
SavegameEditor={
Name:'The legend of Zelda: Tears of the Kingdom',
@ -512,34 +513,23 @@ SavegameEditor={
},
editItem:function(item){
document.querySelector("#header").classList.add("disable-pointer");
document.querySelector(".edit-item-mask").classList.add("show-mask");
this.searchFilter.style.paddingRight = "0px"
currentEditingItem=item;
/* prepare edit item selector */
if(this.selectItem.lastCategory !== item.category){
this.selectItem.innerHTML='';
var itemList=this.getAvailableItems(item.category);
for(var i=0; i<itemList.length; i++){
var opt=document.createElement('option');
opt.value=itemList[i];
opt.innerHTML=_(itemList[i]);
this.selectItem.appendChild(opt);
}
this.updateFilterList();
if(this.selectItem.lastCategory !== item.category){
this.selectItem.lastCategory=item.category;
}
this.selectItem.value=item.id;
if(!this.selectItem.value){
var opt=document.createElement('option');
opt.value=item.id;
opt.innerHTML='Unknown: '+item.id;
this.selectItem.appendChild(opt);
this.selectItem.value=item.id;
}
item._htmlItemId.style.display='none';
item._htmlRow.children[0].appendChild(this.selectItem);
this.selectItem.focus();
this.selectItem.click();
this.selectItem.querySelector(".search-input").setAttribute("placeholder",_(item.id));
this.selectItem.querySelector(".search-input").focus();
this.selectItem.querySelector(".search-input").click();
item.lastInputChanged='id';
for(var prop in item._htmlInputs){
@ -547,6 +537,65 @@ SavegameEditor={
}
},
getName: function(el){
if(!this.nameMap){
this.nameMap = new Map();
}
let name = this.nameMap.get(el);
if(name){
return name;
} else {
name = _(el);
this.nameMap.set(el, name);
return name;
}
},
updateFilterList: function(){
this.searchFilter.innerHTML = "";
var itemList=this.getAvailableItems(currentEditingItem.category);
var filterList = itemList.filter(el => this.getName(el).toLowerCase().includes(inputFilter));
filterList.forEach(el => {
var option = document.createElement("div");
option.classList.add("option");
option.setAttribute("itemId",el);
option.addEventListener("click", (event) => {
var itemId = event.target.getAttribute("itemid")
if(itemId){
currentEditingItem.id = itemId;
document.querySelector(".edit-item-mask").classList.remove("show-mask");
document.querySelectorAll(".disable-pointer").forEach(el => {
el.classList.remove("disable-pointer");
})
var endEvent = new Event("editItemEnd");
this.searchInput.dispatchEvent(endEvent);
this.searchInput.value = "";
inputFilter = "";
}
})
var pic = new Image();
pic.className='item-icon';
pic.loading='lazy';
pic.onerror=function(){
this.src=ICON_PATH+'unknown.png';
}
if(currentEditingItem instanceof Armor){
pic.src = Pouch.getItemIcon(new Armor(Object.assign({...currentEditingItem},{id:el})));
} else {
pic.src = Pouch.getItemIcon(Object.assign({...currentEditingItem},{id:el}));
}
option.appendChild(pic);
var name = document.createElement("span");
name.classList.add("item-name");
name.innerText = this.getName(el);
option.appendChild(name);
this.searchFilter.appendChild(option);
})
},
restoreDurability:function(equipment){
if(equipment.restoreDurability()){
Pouch.updateItemRow(equipment);
@ -570,7 +619,6 @@ SavegameEditor={
Pouch.updateItemIcon(equipment);
return true;
}
return false;
},
restoreDecayAll:function(){
@ -1075,24 +1123,140 @@ SavegameEditor={
this.selectItem=document.createElement('select');
this.selectItem.addEventListener('change', function(){
//console.log('change');
currentEditingItem.id=this.value;
Pouch.updateItemIcon(currentEditingItem);
}, false);
this.selectItem.addEventListener('blur', function(){
//console.log('blur');
var editMask = document.createElement("div");
editMask.classList.add("edit-item-mask");
document.body.appendChild(editMask);
editMask.addEventListener("click", (event) => {
var endEvent = new Event("editItemEnd");
this.searchInput.dispatchEvent(endEvent);
this.searchInput.value = "";
inputFilter = "";
document.querySelectorAll(".disable-pointer").forEach(el => {
el.classList.remove("disable-pointer");
})
editMask.classList.remove("show-mask");
})
this.selectItem = document.createElement('div');
this.selectItem.classList.add("editItem")
this.searchInput = document.createElement("input");
this.searchInput.classList.add("search-input");
this.selectItem.appendChild(this.searchInput);
this.searchFilter = document.createElement("div");
this.searchFilter.classList.add("search-filter");
this.selectItem.appendChild(this.searchFilter);
var keyList = new Set([13,27,38,40])
this.selectItem.addEventListener("mousemove", (event)=>{
if(event.target.className.includes("option") && !event.target.className.includes("active")){
var activeEl = this.selectItem.querySelector(".active")
if(activeEl){
activeEl.classList.remove("active");
}
event.target.classList.add("active");
}
})
this.selectItem.addEventListener("keydown", (event)=>{
var activeEl = this.searchFilter.querySelector(".active");
if(keyList.has(event.keyCode)){
switch(event.keyCode){
case 13:
// enter
if(activeEl){
activeEl.click();
} else {
document.querySelector(".edit-item-mask").click();
}
break;
case 27:
// esc
document.querySelector(".edit-item-mask").click();
break;
case 38:
// up
event.preventDefault();
if(activeEl){
if(activeEl.previousElementSibling){
activeEl.classList.remove("active");
activeEl.previousElementSibling.classList.add("active");
} else {
activeEl.classList.remove("active");
this.searchFilter.querySelector(".option:last-child").classList.add("active");
}
} else {
var firstEl = this.searchFilter.querySelector(".option:first-child")
if(firstEl){
firstEl.classList.add("active");
}
}
break;
case 40:
// down
event.preventDefault();
if(activeEl){
if(activeEl.nextElementSibling){
activeEl.classList.remove("active");
activeEl.nextElementSibling.classList.add("active");
} else {
activeEl.classList.remove("active");
this.searchFilter.querySelector(".option:first-child").classList.add("active");
}
} else {
var firstEl = this.searchFilter.querySelector(".option:first-child")
if(firstEl){
firstEl.classList.add("active");
}
}
break;
}
activeEl = this.searchFilter.querySelector(".active");
// scrollOffset
if(activeEl){
var optionOffsetTop = activeEl.offsetTop;
var optionHeight = activeEl.offsetHeight;
var optionOffsetBottom = optionOffsetTop + optionHeight;
var filterScrollTop = this.searchFilter.scrollTop;
var filterHeight = this.searchFilter.offsetHeight
var filterScrollBottom = filterScrollTop + filterHeight;
if(optionOffsetBottom > filterScrollBottom){
this.searchFilter.scrollTo({
top: optionOffsetBottom - filterHeight + 8,
behavior: event.repeat ? "instant" : "smooth",
})
} else if(optionOffsetTop < filterScrollTop){
this.searchFilter.scrollTo({
top: optionOffsetTop - 8,
behavior: event.repeat ? "instant" : "smooth",
})
}
}
}
})
this.searchInput.addEventListener("input",(event)=>{
inputFilter = event.target.value;
this.updateFilterList();
if(this.searchFilter.clientHeight >= this.searchFilter.scrollHeight){
this.searchFilter.style.paddingRight = "8px"
} else {
this.searchFilter.style.paddingRight = "0px"
}
})
this.searchInput.addEventListener('editItemEnd', function(){
Pouch.updateItemIcon(currentEditingItem);
for(var prop in currentEditingItem._htmlInputs){
currentEditingItem._htmlInputs[prop].disabled=false;
}
Pouch.updateItemRow(currentEditingItem);
SavegameEditor.fixItemAvailabilityFlag(currentEditingItem);
currentEditingItem._htmlItemId.style.display='inline';
this.parentElement.removeChild(this);
this.parentElement.parentElement.removeChild(this.parentElement);
currentEditingItem=null;
}, false);