v0.16.63
Feat (user): add option to change group name Feat (user): add option to change group description Feat (dev): add new component 'text-field' for quick editing text
This commit is contained in:
parent
64c108ae59
commit
34aadc61f1
28
css/main.css
28
css/main.css
@ -313,13 +313,6 @@ sm-popup sm-input + sm-input {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
sm-button {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
sm-button .icon {
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
|
||||
sm-button[variant=primary] {
|
||||
--foreground-color: 255, 255, 255;
|
||||
}
|
||||
@ -671,14 +664,11 @@ sm-button[variant=primary] .icon {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
#contact_details_popup #contact_name {
|
||||
border-radius: 0.5rem;
|
||||
max-width: 30ch;
|
||||
padding: 0.6rem 1.2rem;
|
||||
overflow-wrap: break-word;
|
||||
margin: 0.6rem 0;
|
||||
}
|
||||
#contact_details_popup #contact_name:focus {
|
||||
outline: none;
|
||||
background: rgba(var(--text-color), 0.1);
|
||||
#contact_details_popup #contact_name::part(text) {
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#warn_no_encryption, .date-card, .group-event-card {
|
||||
@ -1215,6 +1205,7 @@ sm-button[variant=primary] .icon {
|
||||
border-color: var(--accent-color) transparent transparent transparent;
|
||||
}
|
||||
#chat .received {
|
||||
margin-right: auto;
|
||||
background: rgba(var(--text-color), 0.1);
|
||||
border-radius: 0 0.8rem 0.8rem 0.8rem;
|
||||
}
|
||||
@ -1283,7 +1274,7 @@ sm-button[variant=primary] .icon {
|
||||
}
|
||||
|
||||
#scroll_to_bottom {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
right: 0;
|
||||
bottom: 4rem;
|
||||
@ -1373,10 +1364,6 @@ sm-button[variant=primary] .icon {
|
||||
padding: 0 1rem;
|
||||
}
|
||||
|
||||
#messages_container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#emoji_picker {
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
@ -1828,7 +1815,8 @@ sm-panel {
|
||||
}
|
||||
|
||||
.navbar-item:hover,
|
||||
.contact:hover {
|
||||
.contact:hover,
|
||||
.emoji:hover {
|
||||
cursor: pointer;
|
||||
background: rgba(var(--text-color), 0.06);
|
||||
}
|
||||
|
||||
2
css/main.min.css
vendored
2
css/main.min.css
vendored
File diff suppressed because one or more lines are too long
@ -268,12 +268,6 @@ sm-popup{
|
||||
flex-direction: column;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
sm-button{
|
||||
margin: 1rem 0;
|
||||
.icon{
|
||||
margin-right: 0.4rem;
|
||||
}
|
||||
}
|
||||
sm-button[variant="primary"]{
|
||||
--foreground-color: 255, 255, 255;
|
||||
.icon{
|
||||
@ -623,13 +617,10 @@ sm-button[variant="primary"]{
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
#contact_name{
|
||||
border-radius: 0.5rem;
|
||||
max-width: 30ch;
|
||||
padding: 0.6rem 1.2rem;
|
||||
overflow-wrap: break-word;
|
||||
&:focus{
|
||||
outline: none;
|
||||
background: rgba(var(--text-color), 0.1);
|
||||
margin: 0.6rem 0;
|
||||
&::part(text){
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1149,6 +1140,7 @@ sm-button[variant="primary"]{
|
||||
}
|
||||
}
|
||||
.received{
|
||||
margin-right: auto;
|
||||
background: rgba(var(--text-color), 0.1);
|
||||
border-radius: 0 0.8rem 0.8rem 0.8rem;
|
||||
&::after{
|
||||
@ -1216,7 +1208,7 @@ sm-button[variant="primary"]{
|
||||
}
|
||||
}
|
||||
#scroll_to_bottom{
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
display: flex;
|
||||
right: 0;
|
||||
bottom: 4rem;
|
||||
@ -1304,9 +1296,6 @@ sm-button[variant="primary"]{
|
||||
flex: 1;
|
||||
padding: 0 1rem;
|
||||
}
|
||||
#messages_container{
|
||||
height: 100%;
|
||||
}
|
||||
#emoji_picker{
|
||||
display: grid;
|
||||
gap: 1rem;
|
||||
@ -1728,7 +1717,8 @@ sm-panel{
|
||||
}
|
||||
}
|
||||
.navbar-item:hover,
|
||||
.contact:hover{
|
||||
.contact:hover,
|
||||
.emoji:hover{
|
||||
cursor: pointer;
|
||||
background: rgba(var(--text-color), 0.06);
|
||||
}
|
||||
|
||||
170
index.html
170
index.html
@ -219,12 +219,8 @@
|
||||
</header>
|
||||
<div class="flex direction-column align-center">
|
||||
<div id="contact_initial" class="initial flex align-center"></div>
|
||||
<h4 id="contact_name" ondblclick="setNameEditable()"></h4>
|
||||
<text-field id="contact_name"></text-field>
|
||||
<div class="flex space-between align-center">
|
||||
<svg tooltip="Edit" id="edit_contact_name" class="icon" onclick="setNameEditable()" viewBox="0 0 64 64">
|
||||
<path
|
||||
d="M46.73,14.81l7,7,7.65-7.6A7.15,7.15,0,0,0,61.39,4L60.11,2.77a7.23,7.23,0,0,0-10.19,0L3.87,48.57a5,5,0,0,0-1.39,2.6L.53,61.27a1.74,1.74,0,0,0,2,2l10.15-1.94A5.06,5.06,0,0,0,15.34,60L49.6,25.9" />
|
||||
</svg>
|
||||
<svg id="delete_person" onclick="deleteChat()" class="icon" viewBox="0 0 64 64" title="Remove">
|
||||
<title>remove</title>
|
||||
<line x1="4" y1="6.3" x2="60" y2="6.3" />
|
||||
@ -456,7 +452,7 @@
|
||||
<footer id="chat_footer" class="grid">
|
||||
<div id="emoji_picker" class="hide-completely"></div>
|
||||
<div class="flex">
|
||||
<svg id="emoji_toggle" onclick="toggleEmoji()" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32,0A32,32,0,1,0,64,32,32,32,0,0,0,32,0ZM43.84,17.51a4.92,4.92,0,1,1-4.92,4.92A4.92,4.92,0,0,1,43.84,17.51Zm-23.62-.06a5,5,0,1,1-5,5A5,5,0,0,1,20.22,17.45ZM32,54.42A19.68,19.68,0,0,1,12.31,34.73H51.69A19.68,19.68,0,0,1,32,54.42Z"/></svg>
|
||||
<svg id="emoji_toggle" onclick="toggleEmoji('toggle')" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M32,0A32,32,0,1,0,64,32,32,32,0,0,0,32,0ZM43.84,17.51a4.92,4.92,0,1,1-4.92,4.92A4.92,4.92,0,0,1,43.84,17.51Zm-23.62-.06a5,5,0,1,1-5,5A5,5,0,0,1,20.22,17.45ZM32,54.42A19.68,19.68,0,0,1,12.31,34.73H51.69A19.68,19.68,0,0,1,32,54.42Z"/></svg>
|
||||
<sm-textarea id="type_message" placeholder="Type a message" class="rest"></sm-textarea>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="send_message_button" class="icon" viewBox="0 0 64 64">
|
||||
<path d="M63.34,31,3.07,4.71A2.19,2.19,0,0,0,.18,7.58L8.94,28.29,42.18,32,8.94,35.71.18,56.42a2.19,2.19,0,0,0,2.89,2.87L63.34,33A1.09,1.09,0,0,0,63.34,31Z"/>
|
||||
@ -490,17 +486,16 @@
|
||||
</div>
|
||||
<div id="group_description_card" class="card hide-completely">
|
||||
<h4>Group description</h4>
|
||||
<p id="group_description"></p>
|
||||
<text-field id="group_description"></text-field>
|
||||
</div>
|
||||
<div id="group_members_card" class="card hide-completely">
|
||||
<div class="flex align-center">
|
||||
<h4>Group members</h4>
|
||||
<sm-button class="admin-option justify-right round">Add member</sm-button>
|
||||
</div>
|
||||
<h4>Group members</h4>
|
||||
<div id="group_members_list"></div>
|
||||
<sm-button class="admin-option">Add member</sm-button>
|
||||
</div>
|
||||
<div class="card">
|
||||
<sm-button>Clear chat</sm-button>
|
||||
<sm-button>Delete chat</sm-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -770,14 +765,21 @@
|
||||
|
||||
switch (e.detail.popup.id) {
|
||||
case 'contact_details_popup':
|
||||
if(floGlobals.groups[clickedContact.floID])
|
||||
if(clickedContact.isGroup){
|
||||
getRef("contact_initial").innerHTML = `
|
||||
<svg class="icon group-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path d="M13.61,28.09c-1.63,0-4.72-2.35-5.33-3.58a21.65,21.65,0,0,1-1.35-7.32s-.26-6.07,6.68-6.07a6.38,6.38,0,0,1,6.69,6.07A21.65,21.65,0,0,1,19,24.51c-.62,1.23-3.7,3.58-5.34,3.58"/><path d="M50.39,28.09c-1.64,0-4.72-2.35-5.34-3.58a21.9,21.9,0,0,1-1.35-7.32s-.26-6.07,6.69-6.07a6.37,6.37,0,0,1,6.68,6.07,21.65,21.65,0,0,1-1.35,7.32c-.61,1.23-3.7,3.58-5.33,3.58"/><path d="M32,31.74c-2.21,0-6.37-3.17-7.2-4.83A29.3,29.3,0,0,1,23,17s-.35-8.21,9-8.21c8.68,0,9,8.21,9,8.21a29.3,29.3,0,0,1-1.83,9.88c-.82,1.66-5,4.83-7.2,4.83"/><path d="M48.29,38.58c-4.16-1.83-8.57-3.08-10.34-6.4a12,12,0,0,1-6,3.73,12,12,0,0,1-5.95-3.73c-1.77,3.32-6.18,4.57-10.34,6.4-1.7.71-3.11,9.88-1.13,9.88A33.06,33.06,0,0,0,31.23,53h1.54a33.06,33.06,0,0,0,16.65-4.53C51.4,48.46,50,39.29,48.29,38.58Z"/><path d="M14.82,36.57c.76-.33,1.54-.65,2.3-1,2.49-1,4.85-2,6.22-3.44C21.07,31.23,19,30.25,18,28.41a8.83,8.83,0,0,1-4.41,2.76,8.83,8.83,0,0,1-4.4-2.76c-1.31,2.46-4.58,3.38-7.66,4.74-1.26.52-2.3,7.31-.84,7.31a24.55,24.55,0,0,0,10.86,3.31C11.89,40.81,12.86,37.39,14.82,36.57Z"/><path d="M62.45,33.15c-3.08-1.36-6.35-2.28-7.66-4.74a8.83,8.83,0,0,1-4.4,2.76A8.83,8.83,0,0,1,46,28.41c-1,1.84-3,2.82-5.32,3.76,1.37,1.43,3.73,2.41,6.22,3.44.76.31,1.54.63,2.26,1,2,.83,3,4.25,3.29,7.21a24.55,24.55,0,0,0,10.86-3.31C64.75,40.46,63.71,33.67,62.45,33.15Z"/></svg>
|
||||
`
|
||||
else
|
||||
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
|
||||
if(floGlobals.groups[clickedContact['floID']].admin === myFloID)
|
||||
getRef('contact_name').disabled = false
|
||||
else
|
||||
getRef('contact_name').disabled = true
|
||||
}
|
||||
else{
|
||||
getRef('contact_name').disabled = false
|
||||
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
|
||||
}
|
||||
getRef('contact_initial').setAttribute('style', `background: ${clickedContact['card'].getAttribute('background-color')}`)
|
||||
getRef('contact_name').textContent = clickedContact['name']
|
||||
getRef('contact_name').value = clickedContact['name']
|
||||
getRef('contact_flo_id').textContent = clickedContact['floID']
|
||||
break;
|
||||
}
|
||||
@ -788,7 +790,8 @@
|
||||
let thisPopup = e.detail.popup
|
||||
switch (e.detail.popup.id) {
|
||||
case 'contact_details_popup':
|
||||
clickedContact['name'] = getRef('contact_name').textContent
|
||||
clickedContact['name'] = getRef('contact_name').value.trim()
|
||||
getRef('contact_name').revert()
|
||||
break;
|
||||
}
|
||||
})
|
||||
@ -1369,7 +1372,7 @@
|
||||
.catch(error => console.error(error))
|
||||
if(prepend){
|
||||
getRef('chat_container').prepend(card);
|
||||
activeChat['receiver'] = floID
|
||||
activeChat['floID'] = floID
|
||||
if(activeChat['chatCard'])
|
||||
activeChat['chatCard'].classList.remove('active')
|
||||
getRef('chat_container').children[0].classList.add('active')
|
||||
@ -1381,7 +1384,7 @@
|
||||
}
|
||||
},
|
||||
messageBubble(msg){
|
||||
let {admin = false, newMembers = [], groupID, name, sender, floID, message, time: timestamp, category, unconfirmed = false, updateChatCard = false} = msg
|
||||
let {admin = false, newMembers = [], groupID, name, description, sender, floID, message, time: timestamp, category, unconfirmed = false, updateChatCard = false} = msg
|
||||
let card = getRef('message_template').content.cloneNode(true),
|
||||
cardContainer = card.querySelector('.message'),
|
||||
messageContent = cardContainer.children[0],
|
||||
@ -1478,6 +1481,12 @@
|
||||
eventCard.textContent = `Changed group name to '${name}'`
|
||||
return eventCard
|
||||
}
|
||||
else if(description){
|
||||
let eventCard = document.createElement('p')
|
||||
eventCard.classList.add('group-event-card')
|
||||
eventCard.textContent = `Changed group description to '${description}'`
|
||||
return eventCard
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
@ -1707,11 +1716,7 @@
|
||||
}
|
||||
// detect click outside emoji panel and emoji button
|
||||
if(isEmojiPickerOpen && (!e.target.closest('#emoji_picker') && !e.target.closest('#emoji_toggle') && !e.target.closest('#type_message'))){
|
||||
isEmojiPickerOpen = false
|
||||
getRef('emoji_toggle').classList.remove('active')
|
||||
getRef('emoji_picker').classList.add('hide-completely')
|
||||
if(!chatScrollInfo.isScrolledUp)
|
||||
scrollToBottom()
|
||||
toggleEmoji('hide')
|
||||
}
|
||||
})
|
||||
|
||||
@ -1734,6 +1739,8 @@
|
||||
clickedContact['card'] = contact
|
||||
clickedContact['floID'] = contact.getAttribute("flo-id")
|
||||
clickedContact['name'] = contact.getAttribute("name")
|
||||
clickedContact['isGroup'] = floGlobals.groups.hasOwnProperty(clickedContact['floID'])
|
||||
|
||||
if(clickedContact['floID'] === myFloID) return
|
||||
if(e.target.closest(".initial") || e.target.closest(".menu")){
|
||||
showPopup('contact_details_popup')
|
||||
@ -1937,13 +1944,20 @@
|
||||
}
|
||||
renderRecentEmojis()
|
||||
|
||||
function toggleEmoji(button){
|
||||
getRef('emoji_toggle').classList.toggle('active')
|
||||
getRef('emoji_picker').classList.toggle('hide-completely')
|
||||
if(getRef('emoji_picker').classList.contains('hide-completely'))
|
||||
isEmojiPickerOpen = false
|
||||
else
|
||||
isEmojiPickerOpen = true
|
||||
function toggleEmoji(mode){
|
||||
switch(mode){
|
||||
case 'toggle':
|
||||
isEmojiPickerOpen = true
|
||||
getRef('emoji_toggle').classList.toggle('active')
|
||||
getRef('emoji_picker').classList.toggle('hide-completely')
|
||||
break;
|
||||
case 'hide':
|
||||
isEmojiPickerOpen = false
|
||||
getRef('emoji_toggle').classList.remove('active')
|
||||
getRef('emoji_picker').classList.add('hide-completely')
|
||||
break;
|
||||
}
|
||||
getRef('scroll_to_bottom').setAttribute('style', `bottom: calc(${window.innerHeight - getRef('chat_footer').getBoundingClientRect().top}px - .5rem)`)
|
||||
if(!chatScrollInfo.isScrolledUp)
|
||||
scrollToBottom()
|
||||
}
|
||||
@ -2176,7 +2190,7 @@
|
||||
function sendMessage() {
|
||||
if(window.innerWidth > 640)
|
||||
getRef('type_message').focusIn()
|
||||
let receiver = activeChat['receiver']
|
||||
let receiver = activeChat['floID']
|
||||
let container;
|
||||
let message = getRef('type_message').value.trim();
|
||||
getRef('type_message').value = ''
|
||||
@ -2184,11 +2198,11 @@
|
||||
let time = Date.now()
|
||||
let msgObj = {message, time, unconfirmed: true}
|
||||
if(activeChat.isGroup){
|
||||
msgObj['groupID'] = activeChat.receiver
|
||||
msgObj['groupID'] = activeChat.floID
|
||||
msgObj['sender'] = myFloID
|
||||
}
|
||||
else{
|
||||
msgObj['floID'] = activeChat.receiver
|
||||
msgObj['floID'] = activeChat.floID
|
||||
msgObj['category'] = 'sent'
|
||||
}
|
||||
getRef('messages_container').append(render.messageBubble(msgObj))
|
||||
@ -2285,7 +2299,7 @@
|
||||
|
||||
function scrollToBottom(){
|
||||
if(activeChat.chatCard){
|
||||
messenger.removeMark(activeChat.receiver, 'unread')
|
||||
messenger.removeMark(activeChat.floID, 'unread')
|
||||
activeChat.chatCard.classList.remove('unread')
|
||||
}
|
||||
getRef('scroll_to_bottom').classList.remove('new-message')
|
||||
@ -2322,7 +2336,7 @@
|
||||
for (let i = startIndex; i < endIndex; i++) {
|
||||
let {floID, groupID, sender, message, time, category} = messages[i]
|
||||
//Stops message from rendering in wrong chat window
|
||||
if(activeChat['receiver'] && ( activeChat['receiver'] === floID || activeChat['receiver'] === groupID)){
|
||||
if(activeChat['floID'] && ( activeChat['floID'] === floID || activeChat['floID'] === groupID)){
|
||||
if(updateChatCard && activeChat.isGroup && message && sender === myFloID) return
|
||||
frag.append(render.messageBubble({...messages[i], updateChatCard}))
|
||||
}
|
||||
@ -2356,7 +2370,7 @@
|
||||
chatCard.querySelector('.last-message').textContent = finalMessage
|
||||
chatCard.querySelector('.time').textContent = getFormatedTime(time, true)
|
||||
|
||||
if(activeChat.receiver === (floID || groupID)){
|
||||
if(activeChat.floID === (floID || groupID)){
|
||||
if(chatScrollInfo.isScrolledUp)
|
||||
getRef('scroll_to_bottom').classList.add('new-message')
|
||||
else{
|
||||
@ -2426,7 +2440,7 @@
|
||||
textColor = contact.getAttribute('text-color'),
|
||||
backgroundColor = contact.getAttribute('background-color')
|
||||
|
||||
activeChat['receiver'] = floID
|
||||
activeChat['floID'] = floID
|
||||
getRef("chat_flo_id").textContent = floID
|
||||
activeChat['isGroup'] = floGlobals.groups[floID] ? true : false
|
||||
if(activeChat.isGroup){
|
||||
@ -2451,7 +2465,7 @@
|
||||
|
||||
getRef("group_description_card").classList.remove('hide-completely')
|
||||
getRef("group_members_card").classList.remove('hide-completely')
|
||||
getRef("group_description").textContent = floGlobals.groups[floID].description;
|
||||
getRef("group_description").value = floGlobals.groups[floID].description;
|
||||
}
|
||||
else{
|
||||
getRef("receiver_initial").textContent = getContactName(floID).charAt(0);
|
||||
@ -2679,40 +2693,61 @@
|
||||
getRef('navbar_backdrop').classList.toggle('hide')
|
||||
}
|
||||
|
||||
function setNameEditable() {
|
||||
if (!getRef('contact_name').isContentEditable) {
|
||||
getRef('contact_name').contentEditable = 'true'
|
||||
getRef('contact_name').focus()
|
||||
document.execCommand('selectAll', false, null);
|
||||
clickedContact['name'] = getRef('contact_name').textContent
|
||||
|
||||
document.addEventListener('contentchanged', e => {
|
||||
if (e.target.closest('#contact_name')) {
|
||||
changeContactName(e.detail.value.trim())
|
||||
}
|
||||
}
|
||||
|
||||
async function changeContactName() {
|
||||
clickedContact['name'] = getRef('contact_name').textContent.trim()
|
||||
if (clickedContact['name'] === '')
|
||||
clickedContact['name'] = 'Unknown'
|
||||
messenger.storeContact(clickedContact['floID'], clickedContact['name']).then(result => {
|
||||
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
|
||||
document.querySelectorAll(`.contact[flo-id="${clickedContact['floID']}"]`).forEach(contact => {
|
||||
contact.children[0].textContent = clickedContact['name'].charAt(0)
|
||||
contact.children[1].textContent = clickedContact['name']
|
||||
contact.setAttribute('name', clickedContact['name'])
|
||||
else if(e.target.closest('#group_description')){
|
||||
messenger.changeGroupDescription(activeChat.floID, e.detail.value.trim())
|
||||
.then(res => {
|
||||
notify('Changed group description', 'success')
|
||||
})
|
||||
notify('Renamed contact', 'success')
|
||||
})
|
||||
.catch(error => notify(error, "error"));
|
||||
}
|
||||
|
||||
document.getElementById('contact_details_popup').addEventListener('click', e => {
|
||||
if (!e.target.closest('#contact_name') && !e.target.closest('#edit_contact_name')) {
|
||||
if (getRef('contact_name').isContentEditable)
|
||||
getRef('contact_name').contentEditable = 'false'
|
||||
if (clickedContact['name'] !== getRef('contact_name').textContent)
|
||||
changeContactName()
|
||||
.catch(error => notify(error, "error"));
|
||||
}
|
||||
})
|
||||
|
||||
async function changeContactName(name) {
|
||||
clickedContact['name'] = name
|
||||
if (clickedContact['name'] === '')
|
||||
clickedContact['name'] = 'Unknown'
|
||||
if(clickedContact.isGroup){
|
||||
messenger.changeGroupName(clickedContact.floID, name).then(res => {
|
||||
updatechatCards({isGroup: true})
|
||||
notify('Changed group name', 'success')
|
||||
})
|
||||
.catch(error => notify(error, "error"));
|
||||
}
|
||||
else{
|
||||
messenger.storeContact(clickedContact['floID'], clickedContact['name']).then(result => {
|
||||
updatechatCards({isGroup: false})
|
||||
notify('Changed contact name', 'success')
|
||||
})
|
||||
.catch(error => notify(error, "error"));
|
||||
}
|
||||
}
|
||||
|
||||
function updatechatCards({isGroup = false}){
|
||||
if(activeChat.floID && activeChat.floID === clickedContact.floID){
|
||||
getRef('receiver_name').textContent = clickedContact['name']
|
||||
getRef('chat_name').textContent = clickedContact['name']
|
||||
}
|
||||
if(!isGroup){
|
||||
getRef('contact_initial').textContent = clickedContact['name'].charAt(0)
|
||||
if(activeChat.floID && activeChat.floID === clickedContact.floID){
|
||||
getRef('receiver_initial').textContent = clickedContact['name'].charAt(0)
|
||||
getRef('chat_dp').textContent = clickedContact['name'].charAt(0)
|
||||
}
|
||||
}
|
||||
document.querySelectorAll(`.contact[flo-id="${clickedContact['floID']}"]`).forEach(contact => {
|
||||
if(!isGroup){
|
||||
contact.children[0].textContent = clickedContact['name'].charAt(0)
|
||||
contact.children[1].textContent = clickedContact['name']
|
||||
}
|
||||
contact.setAttribute('name', clickedContact['name'])
|
||||
})
|
||||
}
|
||||
|
||||
function toggleSearch(target){
|
||||
getRef(target).classList.toggle('expand')
|
||||
if(getRef(target).classList.contains('expand'))
|
||||
@ -2722,6 +2757,7 @@
|
||||
let isChatDetailsOpen = false
|
||||
function showChatDetails({show, animate= true}){
|
||||
if(show){
|
||||
if(isChatDetailsOpen) return
|
||||
isChatDetailsOpen = true
|
||||
getRef('chat').classList.add('expand-side-panel')
|
||||
getRef('chat_left').classList.add('hide-on-medium')
|
||||
|
||||
@ -253,9 +253,6 @@ border: none;
|
||||
.readonly{
|
||||
pointer-events: none;
|
||||
}
|
||||
input:focus{
|
||||
caret-color: var(--accent-color);
|
||||
}
|
||||
.input:focus-within:not(.readonly){
|
||||
box-shadow: 0 0 0 0.1rem var(--accent-color) inset !important;
|
||||
}
|
||||
@ -623,9 +620,6 @@ textarea{
|
||||
.readonly{
|
||||
pointer-events: none;
|
||||
}
|
||||
textarea:focus{
|
||||
caret-color: var(--accent-color);
|
||||
}
|
||||
.textarea:focus-within:not(.readonly){
|
||||
box-shadow: 0 0 0 0.1rem var(--accent-color) inset;
|
||||
}
|
||||
@ -2037,15 +2031,17 @@ customElements.define('sm-popup', class extends HTMLElement {
|
||||
})
|
||||
}, 300);
|
||||
}
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("popupclosed", {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
popup: this,
|
||||
popupStack: this.popupStack
|
||||
}
|
||||
})
|
||||
)
|
||||
setTimeout(() => {
|
||||
this.dispatchEvent(
|
||||
new CustomEvent("popupclosed", {
|
||||
bubbles: true,
|
||||
detail: {
|
||||
popup: this,
|
||||
popupStack: this.popupStack
|
||||
}
|
||||
})
|
||||
)
|
||||
}, 300);
|
||||
}
|
||||
|
||||
handleTouchStart = (e) => {
|
||||
@ -3502,4 +3498,229 @@ customElements.define('sm-section', class extends HTMLElement {
|
||||
mode: 'open'
|
||||
}).append(section.content.cloneNode(true))
|
||||
}
|
||||
})
|
||||
|
||||
const textField = document.createElement('template')
|
||||
textField.innerHTML = `
|
||||
<style>
|
||||
*{
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.text-field{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.text{
|
||||
padding: 0.6rem 0;
|
||||
transition: background-color 0.3s;
|
||||
border-bottom: 0.15rem solid transparent;
|
||||
overflow-wrap: break-word;
|
||||
word-wrap: break-word;
|
||||
word-break: break-all;
|
||||
word-break: break-word;
|
||||
-moz-hyphens: auto;
|
||||
-webkit-hyphens: auto;
|
||||
hyphens: auto;
|
||||
}
|
||||
.text:focus{
|
||||
outline: none;
|
||||
border-bottom: 0.15rem solid var(--accent-color);
|
||||
}
|
||||
.text:focus-visible{
|
||||
outline: none;
|
||||
background: solid rgba(var(--text-color), 0.06);
|
||||
}
|
||||
.editable{
|
||||
border-bottom: 0.15rem solid rgba(var(--text-color), 0.6);
|
||||
}
|
||||
.icon-container{
|
||||
position: relative;
|
||||
margin-left: 0.5rem;
|
||||
height: 1.8rem;
|
||||
width: 1.8rem;
|
||||
}
|
||||
.icon{
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
fill: none;
|
||||
stroke-width: 6;
|
||||
stroke: rgba(var(--text-color), 1);
|
||||
height: 1.8rem;
|
||||
width: 1.8rem;
|
||||
padding: 0.4rem;
|
||||
overflow: visible;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
.hide{
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
<div class="text-field">
|
||||
<div class="text" part="text"></div>
|
||||
<div class="icon-container">
|
||||
<svg class="edit-button icon" viewBox="0 0 64 64">
|
||||
<title>Edit</title>
|
||||
<path d="M46.73,14.81l7,7,7.65-7.6A7.15,7.15,0,0,0,61.39,4L60.11,2.77a7.23,7.23,0,0,0-10.19,0L3.87,48.57a5,5,0,0,0-1.39,2.6L.53,61.27a1.74,1.74,0,0,0,2,2l10.15-1.94A5.06,5.06,0,0,0,15.34,60L49.6,25.9"/>
|
||||
</svg>
|
||||
<svg class="save-button icon hide" viewBox="0 0 64 64">
|
||||
<title>Save</title>
|
||||
<polyline points="0.35 31.82 21.45 52.98 63.65 10.66"/>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
|
||||
customElements.define('text-field', class extends HTMLElement{
|
||||
constructor(){
|
||||
super()
|
||||
this.attachShadow({
|
||||
mode: 'open'
|
||||
}).append(textField.content.cloneNode(true))
|
||||
|
||||
this.textField = this.shadowRoot.querySelector('.text-field')
|
||||
this.textContainer = this.textField.children[0]
|
||||
this.iconsContainer = this.textField.children[1]
|
||||
this.editButton = this.textField.querySelector('.edit-button')
|
||||
this.saveButton = this.textField.querySelector('.save-button')
|
||||
this.isTextEditable = false
|
||||
this.isDisabled = false
|
||||
}
|
||||
|
||||
static get observedAttributes(){
|
||||
return ['disable']
|
||||
}
|
||||
|
||||
get value(){
|
||||
return this.text
|
||||
}
|
||||
set value(val) {
|
||||
this.text = val
|
||||
this.textContainer.textContent = val
|
||||
this.setAttribute('value', val)
|
||||
}
|
||||
set disabled(val) {
|
||||
this.isDisabled = val
|
||||
if(this.isDisabled)
|
||||
this.setAttribute('disable', '')
|
||||
else
|
||||
this.removeAttribute('disable')
|
||||
}
|
||||
fireEvent = (value) => {
|
||||
let event = new CustomEvent('contentchanged', {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
composed: true,
|
||||
detail: {
|
||||
value
|
||||
}
|
||||
});
|
||||
this.dispatchEvent(event);
|
||||
}
|
||||
|
||||
setEditable = () => {
|
||||
if(this.isTextEditable) return
|
||||
this.textContainer.contentEditable = true
|
||||
this.textContainer.classList.add('editable')
|
||||
this.textContainer.focus()
|
||||
document.execCommand('selectAll', false, null);
|
||||
this.editButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
|
||||
this.editButton.classList.add('hide')
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.saveButton.classList.remove('hide')
|
||||
this.saveButton.animate(this.rotateIn, this.animOptions)
|
||||
}, 100);
|
||||
this.isTextEditable = true
|
||||
}
|
||||
setNonEditable = () => {
|
||||
if (!this.isTextEditable) return
|
||||
this.textContainer.contentEditable = false
|
||||
this.textContainer.classList.remove('editable')
|
||||
|
||||
if (this.text !== this.textContainer.textContent.trim()) {
|
||||
this.setAttribute('value', this.textContainer.textContent)
|
||||
this.text = this.textContainer.textContent.trim()
|
||||
this.fireEvent(this.text)
|
||||
}
|
||||
this.saveButton.animate(this.rotateOut, this.animOptions).onfinish = () => {
|
||||
this.saveButton.classList.add('hide')
|
||||
}
|
||||
setTimeout(() => {
|
||||
this.editButton.classList.remove('hide')
|
||||
this.editButton.animate(this.rotateIn, this.animOptions)
|
||||
}, 100);
|
||||
this.isTextEditable = false
|
||||
}
|
||||
|
||||
revert = () => {
|
||||
if (this.textContainer.isContentEditable) {
|
||||
this.value = this.text
|
||||
this.setNonEditable()
|
||||
}
|
||||
}
|
||||
|
||||
connectedCallback(){
|
||||
this.text
|
||||
if(this.hasAttribute('disable'))
|
||||
this.isDisabled = true
|
||||
else
|
||||
this.isDisabled = false
|
||||
|
||||
this.rotateOut = [
|
||||
{
|
||||
transform: 'rotate(0)',
|
||||
opacity: 1
|
||||
},
|
||||
{
|
||||
transform: 'rotate(90deg)',
|
||||
opacity: 0
|
||||
},
|
||||
]
|
||||
this.rotateIn = [
|
||||
{
|
||||
transform: 'rotate(-90deg)',
|
||||
opacity: 0
|
||||
},
|
||||
{
|
||||
transform: 'rotate(0)',
|
||||
opacity: 1
|
||||
},
|
||||
]
|
||||
this.animOptions = {
|
||||
duration: 300,
|
||||
easing: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',
|
||||
fill: 'forwards'
|
||||
}
|
||||
if (!this.isDisabled) {
|
||||
this.iconsContainer.classList.remove('hide')
|
||||
this.textContainer.addEventListener('dblclick', this.setEditable)
|
||||
this.editButton.addEventListener('click', this.setEditable)
|
||||
this.saveButton.addEventListener('click', this.setNonEditable)
|
||||
}
|
||||
}
|
||||
attributeChangedCallback(name) {
|
||||
if (name === 'disable') {
|
||||
if (this.hasAttribute('disable')) {
|
||||
this.iconsContainer.classList.add('hide')
|
||||
this.textContainer.removeEventListener('dblclick', this.setEditable)
|
||||
this.editButton.removeEventListener('click', this.setEditable)
|
||||
this.saveButton.removeEventListener('click', this.setNonEditable)
|
||||
this.revert()
|
||||
}
|
||||
else {
|
||||
this.iconsContainer.classList.remove('hide')
|
||||
this.textContainer.addEventListener('dblclick', this.setEditable)
|
||||
this.editButton.addEventListener('click', this.setEditable)
|
||||
this.saveButton.addEventListener('click', this.setNonEditable)
|
||||
}
|
||||
}
|
||||
}
|
||||
disconnectedCallback() {
|
||||
this.textContainer.removeEventListener('dblclick', this.setEditable)
|
||||
this.editButton.removeEventListener('click', this.setEditable)
|
||||
this.saveButton.removeEventListener('click', this.setNonEditable)
|
||||
}
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user