How to make header bold on excel when export in angular 12 - spreadsheet

I am trying to make the header in bold in excel while exporting but i am not able find solution, my code is
public exportExcel(jsonData: any[], fileName: string): void {
const ws: XLSX.WorkSheet = XLSX.utils.json_to_sheet(jsonData);
const wb: XLSX.WorkBook = { Sheets: { 'data': ws }, SheetNames: ['data'] };
const excelBuffer: any = XLSX.write(wb, { bookType: 'xlsx', type: 'array',cellStyles:true });
this.saveExcelFile(excelBuffer, fileName);
}
private saveExcelFile(buffer: any, fileName: string): void {
const data: Blob = new Blob([buffer], { type: this.fileType });
FileSaver.saveAs(data, fileName + this.fileExtension);
}
i want to find solution here to add style for header.

Related

click event in custom plugin ckeditor5

I have a custom plugin in ckeditor5.
When user click on toolbar icon my plugin convert selected test to custom element with a custom attribute name comment-id.
this work properly.
Now I want to watch on click element and get comment-id on click and I don't know how can I do that.
this is the code of my custom plugin
import uploadIcon from './message.svg'
import ButtonView from '#ckeditor/ckeditor5-ui/src/button/buttonview'
import Plugin from '#ckeditor/ckeditor5-core/src/plugin'
import Command from '#ckeditor/ckeditor5-core/src/command'
import './comment.css'
export default class CustomFileExporerPlugin extends Plugin {
init() {
const editor = this.editor
const config = editor.config.get('comment')
console.log(editor.editing.view.document.isFocused)
editor.editing.view.document.on('click', a => {
console.log(a)
})
editor.model.schema.extend('$text', { allowAttributes: 'comment' })
editor.conversion.attributeToElement({
model: 'comment',
view: (commentId, writer) => {
debugger
if (writer) {
return writer.writer.createAttributeElement(
'comment',
{
'comment-id': commentId,
class: `ck-comment-marker`
},
{ priority: 5 }
)
}
}
})
editor.commands.add('comment', new CommentCommand(editor))
editor.ui.componentFactory.add('comment', locale => {
const view = new ButtonView(locale)
view.set({
label: 'add comment',
icon: uploadIcon,
tooltip: true
})
view.on('execute', async () => {
editor.editing.view.focus()
let id = await config.callback()
editor.execute('comment', { value: 'comment', id })
})
return view
})
}
}
class CommentCommand extends Command {
refresh() {
const model = this.editor.model
const doc = model.document
this.value = doc.selection.getAttribute('comment')
this.isEnabled = model.schema.checkAttributeInSelection(
doc.selection,
'comment'
)
}
execute(options = {}) {
const model = this.editor.model
const document = model.document
const selection = document.selection
const highlighter = options.value
model.change(writer => {
const ranges = model.schema.getValidRanges(
selection.getRanges(),
'comment'
)
if (selection.isCollapsed) {
const position = selection.getFirstPosition()
if (selection.hasAttribute('comment')) {
const isSameHighlight = value => {
return (
value.item.hasAttribute('comment') &&
value.item.getAttribute('comment') === this.value
)
}
const highlightStart = position.getLastMatchingPosition(
isSameHighlight,
{ direction: 'backward' }
)
const highlightEnd = position.getLastMatchingPosition(isSameHighlight)
const highlightRange = writer.createRange(
highlightStart,
highlightEnd
)
writer.removeAttribute('comment', highlightRange)
writer.removeSelectionAttribute('comment')
} else if (highlighter) {
writer.setSelectionAttribute('comment', highlighter)
}
} else {
for (const range of ranges) {
writer.setAttribute('comment', options, range)
}
}
})
}
}
When rendering editor, you can catch custom plugin click event using below code.
const command = editor.commands.get('comment')
command.on('execute', () => { catch click event in custom plugin})

Handle paste event in vue2-editor

I'm using this text editor https://github.com/davidroyer/vue2-editor that is based on Quilljs
I want to handle the paste event so it pastes only the plain text without any format but seems in the documentation that paste is not a supported event by default.
Is there any way to add the paste event?
I've already tried using v-on:paste in the Editor and adding the Quill custom module Clipboard but haven't had any success.
As I didn't find a way of doing it with the library I did it with the DOM
onPaste() {
const x = document.getElementById("removePasteFormat");
console.log(x);
x.addEventListener("paste", (e) => {
e.stopPropagation();
e.preventDefault();
let text = e.clipboardData.getData("text/plain");
// access the clipboard using the api
if (document.queryCommandSupported("insertText")) {
document.execCommand("insertText", false, text);
} else {
document.execCommand("paste", false, text);
}
});
},
Added the id to the div containing the text editors like this:
<div id="removePasteFormat"> *<<Here goes the text editor component>>* </div>
And register the method on mounted()
mounted() {
this.onPaste();
},
I think it would be good to make a plugin.
I made it simple.
src/utils/vue2Plugin/clipboard.ts
import Delta from 'quill/node_modules/quill-delta';
import Clipboard from 'quill/modules/clipboard';
import { Quill } from 'vue2-editor';
export class CustomClipboardPlugin extends Clipboard {
public quill!: Quill;
public options: any = {};
constructor(quill: Quill) {
super(quill, {
matchers: [],
});
this.quill = quill;
this.quill.root.addEventListener('paste', this.onPaste.bind(this), true);
}
onPaste(event: ClipboardEvent) {
event.preventDefault();
event.stopPropagation();
const range = this.quill.getSelection(true);
if (range === null) return;
let _textHtml;
if (event.clipboardData?.getData('text/html')) {
_textHtml = event.clipboardData?.getData('text/html');
} else if (event.clipboardData?.getData('text/plain')) {
_textHtml = `<p>${event.clipboardData?.getData('text/plain')}</p>`;
}
if (_textHtml) {
const pastedDelta = this.quill.clipboard.convert(_textHtml);
const delta = new Delta()
.retain(range.index)
.delete(range.length)
.concat(pastedDelta);
this.quill.updateContents(delta, Quill.sources.USER);
this.quill.setSelection(delta.length() - range.length, 0, Quill.sources.SILENT);
}
}
}
vue file
<template>
...
<VueEditor
...
:custom-modules="customModulesForEditor"
...
/>
...
</template>
// script
import CustomClipboardPlugin fro 'src/utils/vue2Plugin/clipboard.ts';
...
data() {
return {
customModulesForEditor: [{ alias: 'clipboard', module: CustomClipboardPlugin }],
};
},
...
I was wondering the same and came up with the following solution.
1 - Use the :editorOptions option referenced here
<template>
VueEditor(:editorOptions="editorSettings")
</template>
2 - Fill with the module.clipboard module with the option described here
3 - You can then handle the paste with your personal function (applied after quill's matcher). I've written mine following this answer on github
<script>
data() {
return {
editorSettings: {
modules: {
clipboard: {
matchers: [[Node.ELEMENT_NODE, this.customQuillClipboardMatcher]]
}
}
}
}
},
methods: {
customQuillClipboardMatcher(node, delta) {
delta.ops = delta.ops.map((op) => {
return {
insert: op.insert
}
})
return delta
},
}
</script>

Custom directive to check list length for input types

I tried my best to write a custom directive in apollo server express to validate if an input type field of type [Int] does not have more than max length but do not know if its the right way to do. Appreciate if somebody could help me correct any mistakes in the code below.
// schema.js
directive #listLength(max: Int) on INPUT_FIELD_DEFINITION
input FiltersInput {
filters: Filters
}
input Filters {
keys: [Int] #listLength(max: 10000)
}
// Custom directive
const { SchemaDirectiveVisitor } = require('apollo-server-express');
import {
GraphQLList,
GraphQLScalarType,
GraphQLInt,
Kind,
DirectiveLocation,
GraphQLDirective
} from "graphql";
export class ListLengthDirective extends SchemaDirectiveVisitor {
static getDirectiveDeclaration(directiveName) {
return new GraphQLDirective({
name: directiveName,
locations: [DirectiveLocation.INPUT_FIELD_DEFINITION],
args: {
max: { type: GraphQLInt },
}
});
}
// Replace field.type with a custom GraphQLScalarType that enforces the
// length restriction.
wrapType(field) {
const fieldName = field.astNode.name.value;
const { type } = field;
if (field.type instanceof GraphQLList) {
field.type = new LimitedLengthType(fieldName, type, this.args.max);
} else {
throw new Error(`Not a scalar type: ${field.type}`);
}
}
visitInputFieldDefinition(field) {
this.wrapType(field);
}
}
class LimitedLengthType extends GraphQLScalarType {
constructor(name, type, maxLength) {
super({
name,
serialize(value) {
return type.serialize(value);
},
parseValue(value) {
value = type.serialize(value);
return type.parseValue(value);
},
parseLiteral(ast) {
switch (ast.kind) {
case Kind.LIST:
if (ast.values.length > maxLength) {
throw {
code: 400,
message: `'${name}' parameter cannot extend ${maxLength} values`,
};
}
const arrayOfInts = ast.values.map(valueObj => parseInt(valueObj['value']));
return arrayOfInts;
}
throw new Error('ast kind should be Int of ListValue')
},
});
}
}
Does this look right?
Thanks

How to make first letter in search field Uppercase in Vue

How do I make the first letter in search form an uppercase, Your help will be appreciated.
Below is the code snippet. It's giving an error "Expecting a string or number but array given".
<script>
export default {
name: 'SearchForm',
props: {
msg: String,
},
data() {
return {
searchString: ''
}
},
methods: {
parseSearchString() {
// Trim search string
const trimmedSearchString = this.searchString.trim()
if(trimmedSearchString !== '') {
// Split search string
const searchParams = trimmedSearchString.split(/\s+/)
//Uppercase search string
searchParams.split(' ')
.map(w => w.charAt(0).toUpperCase() + w.slice(1))
.join('<br>');
// Emit event
this.$emit('search', searchParams)
// Reset input field
this.searchString = []
}
}
}
};
</script>

Why could not load data from Adapter into JSONStore?

function getListPhoneNumbers() {
var data = {listContacts:[{name:'Ho Cong Vi',number:'12345666'},{name:'hcv',number:'6543218'}]};
WL.Logger.info('Data:'+JSON.stringify(data));
return data;
}
function addListPhoneNumber(data) {
WL.Logger.debug('Add Data to JSONStore: ' + data);
return;
}
function updateListPhoneNumber(data) {
WL.Logger.debug('Updata Data from JSONStore: ' + data);
return;
}
function deleteListPhoneNumber(data) {
WL.Logger.debug('Delete Data from JSONStore: ' + data);
return;
}
This is my code in main.js:
$('#show-all-btn').on('click', showAllData);
var collectionName = 'Contacts',
collections = {};
collections[collectionName] = {
searchFields: {
name: 'string',
number: 'string'
},
adapter: {
name: 'listPhoneNumbers',
add: 'addListPhoneNumber',
replace: 'updateListPhoneNumber',
remove: 'deleteListPhoneNumber',
load: {
procedure: 'getListPhoneNumbers',
param: [],
key: 'listContacts'
}
}
};
WL.JSONStore.init(collections)
function showAllData() {
$('#show-all-btn').on("click", function() {
$('#info').show();
});
WL.JSONStore.get(collectionName).load().then(function(res) {
alert('ok' + JSON.stringify(res));
}).fail(function(errorObject) {
alert(errorObject);
});
}
This is the error:
[wl.jsonstore] {"src":"load","err":18,"msg":"FAILED_TO_LOAD_INITIAL_DATA_FROM_ADAPTER_INVALID_L‌​OAD_OBJ","col":"Contact","usr":"jsonstore","doc":{},"res":{}
The error message is saying the load object you passed is invalid. This is probably because you passed param instead of params. Notice the s at the end.
Also, this code:
WL.JSONStore.init(collections)
function showAllData() {
$('#show-all-btn').on("click", function() {
$('#info').show();
});
WL.JSONStore.get(collectionName).load().then(function(res) {
alert('ok' + JSON.stringify(res));
}).fail(function(errorObject) {
alert(errorObject);
});
}
Looks wrong, maybe what you meant to write is something like this:
WL.JSONStore.init(collections).then(function () {
WL.JSONStore.get(collectionName).count().then(function (numberOfDocsInCollection) {
if(numberOfDocsInCollection < 1) {
WL.JSONStore.get(collectionName).load().then(function(res) {
//handle success
})
}
})
});
I omitted handling failures for brevity. Note that the load will will duplicate items in the collection if those items already exist, hence the count to check if the collection is empty or not.