MatheusrdSantos / vue-quick-chat

A simple chat component created with Vue.js
MIT License
128 stars 45 forks source link

Feature: Send Image/Attachments... Custom slots? #16

Open martinandersen3d opened 4 years ago

martinandersen3d commented 4 years ago

In my project I have to send pictures in the chat. I do not want to create a fork, but rather improve this project.

Thought it would probably be best to discuss how it can be implemented here first.

My first thought is that we can have two custom slots. One for pictures and one for attachments.


Suggested solution:

step 1 - Register that the user clicked the image button: image

step 2 - the programmer does whatever he wants with the callback.

step 3 - Now it needs to be displayed in the chat..

Here is some possible suggestions/solutions:

- There are custom slots for different file types
- or no slots, but the json define how the "chat buble" will look like.
- Raw HTML components, with a <custom :rawHtml="<i>hi</i>">
- 10 different <custom1>,  <custom2>, <custom3>... slots..

What are your thoughts on that? :-)

MatheusrdSantos commented 4 years ago

Hi, @martinandersen3d It's in my plans to implement such functionalities. However I'm quite busy, so I can't implement it yet (I plan to implement new functionalities at the end of this month). In my opinion, your suggestions are good and I'll follow it.

About step 3, I guess you can have two cases (two slot types):

steps 1 and 2 are ok. Remember that probably the message object will have three new fields:

Thanks for your feedback.

martinandersen3d commented 4 years ago

I completely agree with you.

If we implementing the messageType a fourth option could be "html". Then it is very very customizable.

My client is also talking about video chat in the future. Having the ability to insert raw html, would make it possible to do any custom styling and flexibility. Good for any features, that the client will come up with :D

So to add to your comment:

The challenge is to create a extend-ability that serve many different purposes.. I can't tell if it should be slots or json, but with the Image and attachment, its really good start.

martinandersen3d commented 4 years ago

:on-image-upload :on-file-upload

Tofandel commented 4 years ago

@martinandersen3d Raw html would make it susceptible to XSS attacks, sure it's up to the server/dev to prevent this, but I'd rather not have accidental vulnerabilities, the message display should simply be slotted so the user can have control depending on the message type. Also the markup should be up to the vue component and not the server, v-html is a directive that's clearly stated as not best practice

I would also only add an option :on-file-upload type "function" if it's defined then display the attachment button (which should be slotted as are all other buttons), you will then be free to add two buttons rather than one for each file type

And another option for file types accepted, :file-types which could be defaulted to images (.jpg,.jpeg,.png,.gif)

And maybe another option for :multiple or only one file allowed

I would create a component FileUploadButton which would have a hidden file input and a button icon, inputs => file types, multiple, default slot for text. outputs => on file selected should send the FileList of the input

So the user can reuse this component if they need multiples buttons for different file types like you do

It's a straightforward dev (shouldn't take more than 1-2hour) so feel free to open a PR

martinandersen3d commented 4 years ago

Sounds good.

I do also agree on the raw html.

Links: I think if we make it possible to send links in the chat, then I would be able to forward any "video" chat features, via a link to another router in the application.

Maybe we could add it like: messageType ('image', 'file', 'text') contentUrl (if the message type is 'file' or 'image') and maybe contentSize (the file/image size in kb/mb) LinkUrl: ... LinkText: ... LinkImg:.. I don't know if there could/should be a image in the link, LinkId = Html Element ID LinkClass = Html Element Class participantCanPostClickableLinks:boolean = enable or disable if the user can send CLICKABLE links. Maybe the dev, dont want the user to be able to send clickable links, but at the same time the dev want to send application links to the chat.

I'm not sure what is the best way to do this, in a flexible way..

What do you think?

Tofandel commented 4 years ago

Links is another story. That would be a valid use case for using v-html however the message should be entirely html escaped first

Then it could be parsed with a regex and if you find a link add an tag for the link

When can also give control to users who knows what they are doing to v-html via the message type 'html'

martinandersen3d commented 4 years ago

I just came to mind that vue has what is called a dynamic component. Vue has an "is" tag that it can convert to an HTML element.

Here is the Vue code (html element type is defined in the "IS="):

<div is="a" href = "www .." class = "foo" style = "color: red">
   anything inside component
</ div>

It will be converted to HTML:

<a href="www.." class="foo" style="color:red">
   anything inside component
</a>

Vue does not allow "script" inside the tag, so safety is good.

I think this would be a good, secure and flexible solution.

You can see examples, and documentation here:

Example: image

Tofandel commented 4 years ago

This will not be helpful, Vue is not interpolated in v-html, and it's anyway the same as writtng an a tag, this feature is only useful when you need to change the vue component displayed based on some logic

Tofandel commented 4 years ago

I know how to display links without v-html

Instead of escaping it, just explode the text based on regex, parts that match url can be rendered inside an a, the rest in moustache

martinandersen3d commented 4 years ago

I think we misunderstand each other :D

I 100% agree that we can/should use a regex to make links, based on text that the user writes. That's not what I'm trying to explain :D : D

What I'm trying to do is: To create a solution that allows the external programmer to use the component to create the html messages to suit their needs. So make it as flexible as possible and still maintain the security that you talk about :-)

By using dynamic components, we can solve all of the above problems (- minus the regex), as well as enable other programmer to customize every chat messages look and feel, according to their own needs.

Here's what I'm trying to explain: chat

Now, the solution is not "perfect", since there is edge-cases that it will not solve, but there is a lot of stuff that it CAN do.

Does it make sense? :D

Tofandel commented 4 years ago

Okay I see what you're saying but this poses the problem I mentioned about the server having power over the tags used when this power should be left to vue alone via scoped slots, in the scoped slot you can check the message type and display absolutely any component you want rather than a runtime tag, so it's also more flexible, in fact so flexible that in your scoped slot you could define the solution you thought of and be free to use the message structure to customise the markup But it has the side effect of polluting the message structure => more memory and more data to send

martinandersen3d commented 4 years ago

I actually understand what you are trying to do now :D

I like it, its genius :D

So from the messageType, contentUrl, contentSize, external developers can create an unlimited numbers of different slots, where we can loop through and have different components with different properties. Thats really nice :D

Tofandel commented 4 years ago

Yes basically but not just those properties, since the entire message will be passed as a parameter to the scoped slot, you can use any property you want like this, giving you full control over the markup

<template #messageInner="tpl">
    <!-- If type is text, do the default display, else display is customized -->
    <MessageInner v-if="tpl.message.type == 'text'" v-bind="tpl.message"></MessageInner>
    <span v-else-if="tpl.message.type == 'url'"><a :href="tpl.message.url" rel="noreferer noopener" target="_blank">{{tpl.message.content}}</a></span>
    <span v-else-if="tpl.message.type == 'img'"><img :src="tpl.message.image" :alt="tpl.message.content"></span>
    <!-- ... -->
</template>
Tofandel commented 4 years ago

If it's urgent, you can do a PR and I'll review it, else I can do it later this month

I would change the name of the component MessageDisplay to MessagesList for clarity and add a component MessageDisplay which will only contain the display markup PS: It's this part :

<div class="message-text"
     :style="{background: !message.myself?colors.message.others.bg: colors.message.myself.bg, color: !message.myself?colors.message.others.text: colors.message.myself.text}">
    <p v-if="!message.myself" class="message-username">{{getParticipantById(message.participantId).name}}</p>
    <p v-else class="message-username">{{myself.name}}</p>
    <p>{{message.content}}</p>
</div>

And a MessageTimestamp component

<div class="message-timestamp" :style="{'justify-content': message.myself?'flex-end':'baseline'}">
    {{message.timestamp.format('LT')}}
    <v-icon v-if="asyncMode && message.uploaded" name="check" base-class="icon-sent"/>
    <div v-else-if="asyncMode" class="message-loading"></div>
</div>

So the scoped slot should be declared around MessageDisplay in MessageList, and another slot for the message timestamp

tehceen commented 4 years ago

hi guys is anyone have the updated version with image upload feature. thanks

gabrieljbaker commented 4 years ago

Curious about this image upload feature as well!

martinandersen3d commented 4 years ago

Anybody working on this? Else I will look into it, this month.. Anybody want to join? :-)

@Tofandel nice example :-D

MatheusrdSantos commented 4 years ago

@martinandersen3d I guess nobody is working on this feature. But I'll implement a way of display images on chat, as I said here #22.

martinandersen3d commented 4 years ago

Thanks ;-)

vonec commented 3 years ago

+1 .. it would be great if we can have images + files ... i will try to chip in ... been a while ... happy new year @MatheusrdSantos

vonec commented 3 years ago

I completely agree with you.

If we implementing the messageType a fourth option could be "html". Then it is very very customizable.

My client is also talking about video chat in the future. Having the ability to insert raw html, would make it possible to do any custom styling and flexibility. Good for any features, that the client will come up with :D

So to add to your comment:

  • messageType ('image', 'file', 'text', 'html')
  • contentUrl (if the message type is 'file' or 'image') and maybe
  • contentSize (the file/image size in kb/mb)
  • contentHtml (for custom html)

The challenge is to create a extend-ability that serve many different purposes.. I can't tell if it should be slots or json, but with the Image and attachment, its really good start.

if the html part is only about video embeds we can support oembed / graph data much like facebook and twitter but i thinks its a long way to go

vonec commented 3 years ago

:send-images="true" is enabling the image attatchment but

client.js:97 Error: Cannot linkify undefined - Invalid DOM Node type at linkifyElementHelper (vue-quick-chat.common.js:679) at linkifyElement (vue-quick-chat.common.js:742) at VueComponent.mounted (vue-quick-chat.common.js:16295)

when we try to attatch an image ... am i missing something

vonec commented 3 years ago

https://github.com/MatheusrdSantos/vue-quick-chat/pull/51 waiting for it get merged hope that would solve a small problem