I have a chat on my website that reads from a JSON file and grabs each message and then displays it using Vue.js. However, my problem is that when a user posts a link, it is not contained in an anchor tag <a href=""/>. Therefore it is not clickable.
I saw this post, and I think something like this would work, however, I am not allowed to add any more dependencies to the site. Would there be a way for me to do something similar to this without adding more dependencies?
Code for displaying the message.
<p v-for="msg in messages">
<em class="plebe">
<b> [ {{msg.platform.toUpperCase()}} ]
<span style="color: red" v-if="msg.isadmin">{{msg.user.toUpperCase()}}</span>
<span style="color: #afd6f8" v-else="">{{msg.user.toUpperCase()}}</span>
</b>
</em>:
{{msg.message}}
</p>
In a situation like this, its preferred to write a custom functional component.
The reason for this is the fact that we are required to emit a complex html structure, but we have to make sure to properly protect against xss attacks (so v-html + http regex is out of the picture)
We are also going to use render functions, because render functions have the advantage to allow for javascript that generates the html, having more freedom.
<!-- chatLine.vue -->
<script>
export default {
functional: true,
render: function (createElement, context) {
// ...
},
props: {
line: {
type: String,
required: true,
},
},
};
</script>
<style>
</style>
We now need to think about how to parse the actual chat message, for this purpose, I'm going to use a regex that splits on any length of whitespace (requiring our chat urls to be surrounded with spaces, or that they are at the start or end of line).
I'm now going to make the code in the following way:
Make a list for child componenets
Use a regex to find url's inside the target string
For every url found, do:
If the match isn't at the start, place the text leading from the previous match/start inside the children
place the url inside the list of children as an <a> tag, with the proper href attribute
At the end, if we still have characters left, at them to the list of children too
return our list wrapped inside a P element
Vue.component('chat-line', {
functional: true,
// To compensate for the lack of an instance,
// we are now provided a 2nd context argument.
// https://vuejs.org/v2/guide/render-function.html#createElement-Arguments
render: function (createElement, context) {
const children = [];
let lastMatchEnd = 0;
// Todo, maybe use a better url regex, this one is made up from my head
const urlRegex = /https?:\/\/([a-zA-Z0-9.-]+(?:\/[a-zA-Z0-9.%:_()+=-]*)*(?:\?[a-zA-Z0-9.%:_+&/()=-]*)?(?:#[a-zA-Z0-9.%:()_+=-]*)?)/g;
const line = context.props.line;
let match;
while(match = urlRegex.exec(line)) {
if(match.index - lastMatchEnd > 0) {
children.push(line.substring(lastMatchEnd, match.index));
}
children.push(createElement('a', {
attrs:{
href: match[0],
}
}, match[1])); // Using capture group 1 instead of 0 to demonstrate that we can alter the text
lastMatchEnd = urlRegex.lastIndex;
}
if(lastMatchEnd < line.length) {
// line.length - lastMatchEnd
children.push(line.substring(lastMatchEnd, line.length));
}
return createElement('p', {class: 'chat-line'}, children)
},
// Props are optional
props: {
line: {
required: true,
type: String,
},
},
});
var app = new Vue({
el: '#app',
data: {
message: 'Hello <script>, visit me at http://stackoverflow.com! Also see http://example.com/?celebrate=true'
},
});
.chat-line {
/* Support enters in our demo, propably not needed in production */
white-space: pre;
}
<script src="https://unpkg.com/vue#2.0.1/dist/vue.js"></script>
<div id="app">
<p>Message:</p>
<textarea v-model="message" style="display: block; min-width: 100%;"></textarea>
<p>Output:</p>
<chat-line :line="message"></chat-line>
</div>
You can watch or write computed method for the variable having url and manupulate it to html content and then use v-html to show html content on the page
v-html
I have a string with lots of " which i replace with an empty String and this works.
But I also want to make a line break when a comma appears.
Already tried it with ('\n'), ('\r'), ('<br>'), ('<br/>') but nothing works.
in my angular controller I have the string
self.msg = msg.replace(/"/gi, '').replace(/,/gi, '\n');
self.testAlerts = [{ type: 'success', msg: self.msg}];
I want to show this message in the alert box in my html
<div uib-alert ng-repeat="alert in testAlerts" type="{{alert.type}}" >{{alert.msg}}</div>
Why do the line breaks not work?
Use ng-bind-html instead of interpolation:
<div uib-alert ng-repeat="alert in testAlerts" type="{{alert.type}}" ng-bind-html="alert.msg"></div>
Here's a plunkr for demonstration.
If anybody from Angular world is happen to be here you can use
[innerHTML] instead of [ng-bind-html] from #RamblinRose's answer
Or even, just add css white-space class
<div uib-alert ng-repeat="alert in testAlerts" style="white-space: pre-line;" type="{{alert.type}}" >{{alert.msg}}</div>
I am using HTML textarea for user to input some data and save that to App Engine's model
The problem is that when I retrieve the content it is just text and all formatting is gone
The reason is because in textarea there is no formatting that we can make
Question:
is there any way to retain the format that user provides?
is there any other element(other than textarea), that i'll have to use?(which one?)
P.S I am very new to area of web development and working on my first project
Thank you
What you want is a Rich Text Editor. The standard HTML <textarea> tag only accepts plain text (even if the text is or includes HTML markup). There are a lot of example out there (including some listed on the page linked) but I would highly recommend using a prepackaged one for this. Coding your own is fairly complicated for people who are new, and even for a lot who have some experience. Both TinyMCE and CKEditor are very common ones, but there are many others as well.
A text box is like wordpad, you cant format it, if you paste in from word or any other formatted text it will wipe all the formatting and you will be left with just the text.
You need add an editor to the text areas, I use TinyMCE, but there are many other out there too.
To implement you need to have all the source (which you can get from TinyMCE) in your web directory.
Here's an example which you can try:
Add this the the head section of your page:
<script language="javascript" type="text/javascript" src="/js/tiny_mce/tiny_mce.js"></script>
<script language="javascript" type="text/javascript">
tinyMCE.init({
theme : "advanced",
mode: "exact",
elements : "elm1",
theme_advanced_toolbar_location : "top",
theme_advanced_buttons1 : "bold,italic,underline,strikethrough,separator,"
+ "justifyleft,justifycenter,justifyright,justifyfull,formatselect,"
+ "bullist,numlist,outdent,indent",
theme_advanced_buttons2 : "link,unlink,anchor,image,separator,"
+"undo,redo,cleanup,code,separator,sub,sup,charmap",
theme_advanced_buttons3 : "",
height:"350px",
width:"600px"
});
</script>
<script type="text/javascript">
tinyMCE.init({
// General options
mode : "textareas",
theme : "advanced",
plugins : "autolink,lists,spellchecker,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
// Theme options
theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,spellchecker,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,blockquote,pagebreak,|,insertfile,insertimage",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true,
// Skin options
skin : "o2k7",
skin_variant : "silver",
// Example content CSS (should be your site CSS)
content_css : "css/example.css",
// Drop lists for link/image/media/template dialogs
template_external_list_url : "js/template_list.js",
external_link_list_url : "js/link_list.js",
external_image_list_url : "js/image_list.js",
media_external_list_url : "js/media_list.js",
// Replace values for the template plugin
template_replace_values : {
username : "Some User",
staffid : "991234"
}
});
</script>
Then to call the textarea:
<textarea name="content" style="width:100%">YOUR TEXT HERE</textarea>
NB: You need to download and have in your directory the js files for <script language="javascript" type="text/javascript" src="/js/tiny_mce/tiny_mce.js"></script>
Hope this helps!
This won't solve the case when you want somebody to be able to format their text (e.g. with WYSIWYG bold buttons etc.), but if you want to be able to accept pre-formatted HTML (e.g. copy and paste from other HTML source such as a webpage), then you can do this:
<form ...>
<label>Paste your HTML in the box below</label>
<textarea style='display:none' id='foo'></textarea>
<div id='htmlsource' contenteditable style='border:solid 1px black;padding:1em;width:100%;min-height:2em;' ></div>
<input type='submit' />
</form>
<script>
jQuery(function(){
jQuery('form').submit( function(e) {
jQuery('textarea').val( jQuery('#htmlsource').html() );
});
});
</script>
This uses a contenteditable div element which you can format to look like an input box and will accept pasted HTML, and a hidden textarea#foo which will be populated with the pasted HTML just before the form is submitted.
Note that this is not an accessible solution as it stands.
Depending on your goal for the programm it could already be sufficient to just add "pre" tags left and right to the input of your textarea. for example if your code submits to a form whatever is inside a textarea and than echos it in the target File this would already work.
> File 1:
>
> <form action="Output.php" methode=post>
> <textarea name="Input"></textarea>
> </form>
>
> File Output.php
>
> $UserInput = $_POST["Input"];
> $UserInput = "<pre>" . $UserInput . "</pre>"
> echo $UserInput
this already will retain all Enters for example that where used in the original user input and echo them correctly
If you retrieve the content from the App Engine Saving the Content with the pre tags added already in most cases does the trick
If I have some Markdown like
## My Title
A paragraph of content here.
code_line(1);
// a code comment
class MoreCode { }
and more text to follow...
How can I set a class on the <code> block that's generated in the middle there? I want to have it output
<code class=’prettyprint’>
code_line(1);
// a code comment
class More Code { }
</code>
But I can't seem to set it. I do not have control over the Markdown code being run, only over the content.
You can embed HTML in Markdown. Type literally what you want, with no indent.
<code class="prettyprint">
code_line(1);
// a code comment
class More Code { }
</code>
For the specific case of syntax highlighting following the back ticks at the start of a fenced code block with the language works just about everywhere these days.
```js
code_line(1);
// a code comment
class MoreCode { }
```
Though not answering the question exactly. You can use a different render too like Maruku or Kramdown:
## My Title
A paragraph of content here.
~~~
code_line(1);
// a code comment
class MoreCode { }
~~~
{: .prettyprint}
and more text to follow...
Output (tested with haml & kramdown):
<pre class="prettyprint"><code>
code_line(1);
// a code comment
class MoreCode { }
</code></pre>
Kramdown syntax: http://kramdown.rubyforge.org/quickref.html#block-attributes
Markdown has an extension (attr_list.py) which allows you to use Maruku's {: .classname} syntax.
Markdown Extra supports class and id attributes using curly braces. See: https://michelf.ca/projects/php-markdown/extra/#spe-attr