WYSIWYG editor and innerHTML in Angular 8 - javascript

I'm trying to implement a WYSIWYG editor and show on HTML your content, but I have two main problems... Let's to code...
"Register/Upload component .ts" (I'm using AngularEditor)
editorConfig: AngularEditorConfig = {
editable: true,
spellcheck: true,
height: 'auto',
minHeight: '300px',
maxHeight: 'auto',
width: 'auto',
enableToolbar: true,
showToolbar: true,
placeholder: 'Enter text here...',
sanitize: true,
toolbarPosition: 'top',
toolbarHiddenButtons: [
['strikeThrough', 'superscript', 'subscript'],
['heading', 'fontName', 'fontSize', 'color'],
['justifyFull', 'indent', 'outdent'],
['cut', 'copy', 'delete', 'removeFormat', 'undo', 'redo'],
['paragraph', 'removeBlockquote'],
['textColor', 'backgroundColor'],
['insertImage', 'insertVideo'],
['link', 'unlink', 'image', 'video'],
['toggleEditorMode'],
],
};
"Register/Upload component .html"
<angular-editor
formControlName="description"
[config]="editorConfig"
></angular-editor>
QUESTION 1: Everything here works fine. But when I go to update the value, show a raw HTML inside the editor and not the formated text... How I can fix this?
I another problem, the innerHTML doesn't work with the data came from the database.
<div class="breaklines" [innerHTML]="prop.description | safeHtml"></div> <--- NOT WORK
<div class="breaklines" [innerHTML]="'<strong>text directly</strong>'"></div> <--- WORK, even the same content
I created the pipe to safe html:
import { Pipe, PipeTransform } from '#angular/core';
import { DomSanitizer } from '#angular/platform-browser';
#Pipe({ name: 'safeHtml', pure: false })
export class SafeHtml implements PipeTransform {
constructor(private sanitizer: DomSanitizer) {}
transform(content) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
QUESTION 2: Do I need handler my HTML save on database, before try bind it?
Thanks everybody!
UPDATE
I'm discovery why innerHTML doesn't work with the saved code. When I make get the code comes < instead of < in all HTML tags. Then I make a simple replace and everything work
this.desc = prop.description.replace(/</g, '<');
<div class="breaklines" [innerHTML]="desc | safeHtml"></div>
Now, I only need to know how I can format the html in the editor when I going to update an information... Thanks!

I do not think that saving your html in a database would change anything. It seems like you are currently sanitizing your input twice :
once in SafeHtml
once in your editor config sanitize: true,
You might try to set sanitize to false in the editor config ?

Related

Quill Editor: cannot paste any text, input loses focus

I'm trying to paste any random text into the quill#1.3.7 editor, but all of my paste events are pretty much ignored. In addition, the cursor disappears - ie, the <div> loses focus.
Do I have to do something to get basic/default clipboard paste to work? According the docs, those should be turned on by default since they are required.
I have debug turned on, and this is what I see in Chrome.
Here is how I'm initializing the editor:
<div ref="editorElement" class="ql-editor" contenteditable="true"></div>
import Quill from 'quill';
#customElement('quill-editor')
export class QuillEditorComponent {
#bindable({ defaultBindingMode: bindingMode.twoWay }) value: string;
editorElement: any;
editor: Quill;
attached() {
var toolbarOptions = [/* removed for brevity */];
this.editor = new Quill(this.editorElement, {
debug: true,
modules: {
toolbar: toolbarOptions,
clipboard: {
matchVisual: false
}
},
placeholder: 'I have something to say...',
theme: 'snow'
});
this.editor.root.innerHTML = this.value;
}
}
UPDATE:
Filed an issue, as this seems to be a Chrome related issue:
https://github.com/quilljs/quill/issues/3512

Datatable withbutton hide and show in angularjs code

I am new to angularjs. I am implementing a angularjs datatable with some json data. I am facing a problem that each time if a user had permission (which is stored in json) can export csv but when the user has no permission, the datatable export button is hidden or does not show. I googled some articles but am unable to find answer.
I used below code to implement datatable buttons:
vm.dtOptions = DTOptionsBuilder.fromSource('')
.withFnServerData(serverData)
.withOption('createdRow', createdRow)
.withDataProp('data')
.withOption('order', [0, 'desc'])
.withOption('processing', true)
.withOption('serverSide', true)
.withOption('headerCallback', function(header) {
if (!vm.headerCompiled) {
// Use this headerCompiled field to only compile header once
vm.headerCompiled = true;
$compile(angular.element(header).contents())($scope);
}
})
.withPaginationType('full_numbers')
.withOption('lengthMenu', [
[10, 50, 100, 200, 500, -1],
[10, 50, 100, 200, 500, "All"]
])
.withButtons([
{
className:'fa fa-upload',
key: '1',
action: function (e, dt, node, config) {
vm.openImportFileDialog();
}
},
{
action:function () {
if (!vm.permissions.assets_EDIT) {
alert('You have no permission to download file.')
}
},
extend: "csv",
text:' Export(CSV)',
className:'fa fa-download',
exportOptions: {
columns:[0,1,2,3,4,5,6]
},
exportData: {decodeEntities:true}
},
{
className:'fa fa-exchange p-left-5',
text:' Export(HTML)',
// enabled: false,
action:function () {
vm.openNewTab();
}
}
])
.withBootstrap();
Here is my html content:-
<table datatable="" dt-options="vm.dtOptions" dt-columns="vm.dtColumns" dt-instance="vm.dtInstance"
class="row-border hover">
</table>
Thanks for your precious time.
You should manage two set of buttons, one for users with permissions, another for users without. It could look like this :
var buttonsNoPermission = [{ extend: 'colvis' }];
var buttonsWithPermission = [{ extend: 'colvis' }, { extend: 'csvHtml5' }];
Simply port the params from your .withButtons to variables. Then you can create the relevant buttons for the user by a ternary in the initialization itself :
.withButtons( permissions.asset_EDIT ? buttonsWithPermission : buttonsNoPermission)
Here is a small demo, try change permissions.asset_EDIT :
http://plnkr.co/edit/s6lainDw4eQC9zaoZGdG?p=preview
Note: I am not using the vm approach in the demo, so dont get confused, refer to vm.permissions.asset_EDIT in your own code. Have never really understood the concept behind vm, besides it is a way for lazy programmers to accidently add a new layer of complexity to their code :)
Based on value of say vm.showExportOption you can add a class to the parent table element. Then with a little bit of CSS Logic you can hide the exact button by targeting its class based on whether or not a certain class is present on its parent.
Here's the rough idea:
On Table element:
ng-class="vm.showExportOption ? 'show-export' : 'hide-export'"
Then in CSS something like:
table.show-export .fa-exchange{
display:block;
}
table.hide-export .fa-exchange{
display:none;
}
Remember this is not to copy-paste but to give you an idea on how to do this. If you can create a JSFiddle to show your problem, I will gladly port it, but this should get you on you way.
I would try adding an ng-show tag element tag, in your case the export button, with a backing Boolean variable that you can set in your code:
<table ng-show="!vm.dtIsHidden" datatable="" dt-options="vm.dtOptions" dt-columns="vm.dtColumns" dt-instance="vm.dtInstance"
class="row-border hover">
</table>
Then in your view model, set this value up with the proper logic:
vm.dtIsHidden = whatever;
And this should solve your problem.

Inline HTML data-role <> script jquery: Kendo Widget Initialization

Using Kendo there are two ways to initialize a Kendo Widget:
one:
<span id=”UniqueID” /></span>
<script>
$(“#UniqueID”).KendoWidget();
</script>
two:
<span id=”UniqueID” data-role=”Widget” /></span>
<script>
Kendo.init($(“#UniqueID”));
</script>
Does anybody know the pro's and con's of there two methods?
I want to make sure I am aware of the implications of any specific direction.
and if it's more of less equal, which is the most commonly found mechanism, dev's follow.
Kind Regards,
Flippie
I use both. It depends on the complexity of the configuration for that widget, and in some cases, it's not possible (or at least very difficult) to initialize a widget within the HTML due to data context issues; thus, it's easier to initialize it in code. Other times, it's simply personal preference.
For all widgets, I'll start by declaring them in the HTML, like so:
<div id="cases"
data-role="grid"
data-bind="source: cases"
data-pageable="{ refresh: true }"
data-sortable="{ mode: 'multiple' }"
data-filterable="{
extra: false,
operators: { string: { contains: 'Contains', eq: 'Is equal to' } }
}"
data-columns="[
{ title: '', template: kendo.template($('#editColumnTemplate').html()), sortable: false, filterable: false, width: 42 },
{ field: 'number', title: 'Number', width: 160 },
{ field: 'subject', title: 'Subject' },
{ field: 'contact', title: 'POC', width: 200 },
{ field: 'referral', title: 'Referred By', width: 100 },
{ field: 'opened', title: 'Opened', format: '{0:d}', filterable: false, width: 120 },
{ field: 'closed', title: 'Closed', format: '{0:d}', filterable: false, width: 120 }
]">
</div>
I prefer doing it this way because all of the widget's configuration is declared inline with it's location in the HTML. It's similar in the way that you have to bind data to your view using MVVM frameworks like Kendo and Knockout, so, I like to be consistent. For me, it's easier to maintain because everything is defined in one place and it looks clean. Now, if I run into data context problems where I can't bind a particular observable or data element, say within this grid's columns definition, then I move it all to code.
Either way is more or less equal. I couldn't tell you which is more common. I imagine most developers do it the same way I do - mixing both methods.

How to open a file with epiceditor?

I have the following file structure
And in content.php i have the following JS code
var file = "http://2sense.net/blog/posts/my-second-post.md"
var opts = {
basePath: "http://2sense.net/blog/posts/",
container: 'epiceditor',
textarea: null,
basePath: 'epiceditor',
clientSideStorage: true,
localStorageName: 'epiceditor',
useNativeFullscreen: true,
parser: marked,
file: {
name: 'epiceditor',
defaultContent: '',
autoSave: 100
},
theme: {
base: '/themes/base/epiceditor.css',
preview: '/themes/preview/preview-dark.css',
editor: '/themes/editor/epic-dark.css'
},
button: {
preview: true,
fullscreen: true
},
focusOnLoad: false,
shortcut: {
modifier: 18,
fullscreen: 70,
preview: 80
},
string: {
togglePreview: 'Toggle Preview Mode',
toggleEdit: 'Toggle Edit Mode',
toggleFullscreen: 'Enter Fullscreen'
}
}
window.editor = new EpicEditor(opts);
editor.load(function () {
console.log("Editor loaded.")
});
$("#openfile").on("click", function() {
console.log("openfile");
editor.open(file);
editor.enterFullscreen();
})
When i try to open the file with "editor.open(file);" does not happen anything. And I have verified that the event is triggered proprely when i press the button.
Do you have any idea how to fix this, or do you have a real example... the documentation for the API on the epiceditor website does not say so much.
Cheers
Client side JS cannot open desktop files (or, not easily or cross browser). This would be a nice feature to use with the File API, but that's not implemented. EpicEditor stores "files" in localStorage. When you do editor.open('foo') you're basically doing: JSON.parse(localStorage['epiceditor'])['foo'].content. This has been asked a few times, so I made a ticket to make it more clear in the docs.
https://github.com/OscarGodson/EpicEditor/issues/276
Does that help?
P.S. a pull request with docs that make sense to you are always welcome :)

Sencha Touch 2 - TabPanel does not work in MVC designed App

simple question for you today...
This works:
var carousel = Ext.create('Ext.Carousel', {
fullscreen: 'true',
//load in views view clean instantiation using
// the widget.alias's defined in each view... yea
// For some reason, putting flex on these components... oh...
// Have to call directly in by just the xtype since these are just
// references..
items: [
{
xtype: 'Main'
},
{
xtype: 'CommentList'
}
]
This does NOT work:
var tabpanel = Ext.create('Ext.TabPanel', {
fullscreen: 'true',
tabBarPosition: 'bottom',
defaults: {
styleHtmlContent: true
},
//load in views view clean instantiation using
// the widget.alias's defined in each view... yea
// For some reason, putting flex on these components... oh...
// Have to call directly in by just the xtype since these are just
// references..
items: [
{
xtype: 'Main',
title: 'The Main',
iconCls: 'user'
},
{
xtype: 'CommentList',
title: 'Comments',
iconCls: 'user'
}
]
});
As you can see, they are pretty much the same except one is a TapPanel (with the required default configs added) and the other is a carousel.
Everything else is exactly the same.... This is in the app.js of my Sencha Touch 2.0 app designed following the MVC architecture.
The result of the not-working TabPanel is that I only see the first view (Main) and no tab-bar appears in the bottom of the screen.
Any ideas what my problem might be?
I am not sure if this is an issue but in my code the line is:
Ext.create("Ext.tab.Panel", {
Not:
Ext.create('Ext.TabPanel', {
Fullscreen should be fullscreen: true instead of fullscreen: 'true'. You could also add this code to make them switch:
cardSwitchAnimation: {type: "fade", duration: 1000},
layout: "card",
Didn't test it, but it worked for me (got it from a snippet of my own code)

Categories