How to customize a block component in GrapesJS - grapesjs

blocks: [
{
id: 'hi',
label: 'Customer',
media: ``,
// Use `image` component
content: { type:'text'},
// The component `image` is activatable (shows the Asset Manager).
// We want to activate it once dropped in the canvas.
activate: true,
// select: true, // Default with `activate: true``
model: {
// Default properties
defaults: {
tagName: 'input',
draggable: 'form, form *', // Can be dropped only inside `form` elements
droppable: false, // Can't drop other elements inside
attributes: { // Default attributes
type: 'text',
name: 'default-name'
}
}
},
}
],
How to add text and image as type in this block. So that i can drag and drop a component with both text and image in it?
..content: { type:'text','image'}...

Related

How can you set custom labels for controls in Storybook?

I'm trying to set custom labels for my controls in Storybook as outlined in the instructions here, but it's not working as expected. According to the instructions you can specify control.labels to configure custom labels for your checkbox, radio, or select input.
Right now I have a prop of size that allows the user to select the size of the component, but in Storybook it's showing the number value as opposed to name. e.g.
Instead of the number values I want the labels to read the names from the enum below.
export enum sizes {
small = 32,
default = 50,
large = 100,
};
How can I update Storybook to use the enum sizes name instead of the value?
// storybook
export default {
title: 'Components/Spinner',
component: Spinner,
controls: { expanded: true },
argTypes: {
type: {
options: ['primary', 'secondary', 'success', 'warning', 'danger', 'info', 'light'],
control: { type: 'radio'},
},
size: {
options: [sizes.default, sizes.small, sizes.large],
control: {
type: 'radio',
labels: {
Default: 'Default',
Small: 'Small',
Large: 'Large'
},
},
}
}
} as Meta;
FYI: If I update options to the following:
options: sizes,
I get both the name and the value and only the name works
In case anyone else comes across this issue I solved it by manually typing in the values. According to this Stackoverflow post enums end up as object. So it was outputting both the key and values.
export default {
title: 'Components/Spinner',
component: Spinner,
controls: { expanded: true },
argTypes: {
type: {
options: ['primary', 'secondary', 'success', 'warning', 'danger', 'info', 'light'],
control: { type: 'radio'},
},
size: {
options: [32, 50, 100],
control: {
type: 'radio',
labels: {
32: 'small',
50: 'default',
100: 'large',
},
},
}
}
} as Meta;

Fetch data in React TinyMCE custom dialog

Is it possible to create a custom dialog (React TinyMCE) that fetches data from an API and lists items for the user to select one?
Appearently, TinyMCE only allows me to create a custom dialog with static data.
const internalLinksDialog = editor => ({
title: 'Internal Links',
body: {
type: 'panel',
items: [
{
type: 'input',
name: 'search',
inputMode: 'text',
placeholder: 'Search internal links',
},
// ...render a list with items
],
},
initialData: {
search: '',
items: [], // ...data fetched from an api
},
onSubmit: api => {
const data = api.getData();
editor.execCommand('mceInsertContent', false, `<p>${JSON.stringify(data)}</p>`);
api.close();
},
});

How to add "strinsert" custom dropdown plugin to ckeditor4-react?

I am working with ckeditor4-react plugin to use Text editor inside react app. Now I want to add a string dropdown inside my text editor, for this I have followed the "add custom plugin" documentation and added "strinsert" custom plugin.
Inside "node-modules/ckeditor4-react/" folder I have created a folder with name "plugins" and placed "strinsert" folder inside this.
Now my path of custom plugins is "node-modules/ckeditor4-react/plugins/strinsert/plugin.js"
Code of "plugin.js":
CKEDITOR.plugins.add('strinsert',
{
requires : ['richcombo'],
init : function( editor )
{
// array of strings to choose from that'll be inserted into the editor
var strings = [];
strings.push(['##FAQ::displayList()##', 'FAQs', 'FAQs']);
strings.push(['##Glossary::displayList()##', 'Glossary', 'Glossary']);
strings.push(['##CareerCourse::displayList()##', 'Career Courses', 'Career Courses']);
strings.push(['##CareerProfile::displayList()##', 'Career Profiles', 'Career Profiles']);
// add the menu to the editor
editor.ui.addRichCombo('strinsert',
{
label: 'Insert Content',
title: 'Insert Content',
voiceLabel: 'Insert Content',
className: 'cke_format',
multiSelect:false,
panel:
{
css: [ editor.config.contentsCss, CKEDITOR.skin.getPath('editor') ],
voiceLabel: editor.lang.panelVoiceLabel
},
init: function()
{
this.startGroup( "Insert Content" );
for (var i in strings)
{
this.add(strings[i][0], strings[i][1], strings[i][2]);
}
},
onClick: function( value )
{
editor.focus();
editor.fire( 'saveSnapshot' );
editor.insertHtml(value);
editor.fire( 'saveSnapshot' );
}
});
}
});
After adding this I have used this plugin inside Text editor by using "extraPlugins" config prop. This is a code of my TextEditor plugin file(which is inside the "src" folder of )
class TextEditor extends React.Component {
constructor(props) {
super(props);
this.state = {
editorData: this.props.data
}
}
/** lifecycle method */
componentDidMount() {
this.isMount = true;
this.setState({editorData: this.props.data})
}
componentWillUnmount() {
this.isMount = false;
}
/** function to detect the editor changes */
onEditorChange(event) {
let data = event.editor.getData()
this.props.onChange(data)
}
// main function
render() {
const { editorData } = this.state;
return (
<CKEditor
data={editorData}
onChange={(e) => this.onEditorChange(e)}
config={{
toolbar: [
{ name: 'basicstyles', items: ['Bold', 'Italic', 'Underline', 'Strike'] },
{ name: 'editing', items: ['SelectAll'] },
{ name: 'clipboard', items: ['Undo', 'Redo'] },
{ name: 'links', items: ['Link', 'Unlink', 'Anchor'] },
{ name: 'insert', items: [ 'Image', 'Table', 'HorizontalRule', 'Smiley', 'SpecialChar' ] },
{ name: 'document', items: [ 'Templates', 'Preview', '-', 'Source'] },
{ name: 'paragraph', items: ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', 'Blockquote', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'BidiLtr', 'BidiRtl', 'Language'] },
{ name: 'styles', items: [ 'Styles', 'Format', 'Font', 'FontSize' ] },
{ name: 'colors', items: [ 'TextColor', 'BGColor' ] },
{ name: 'tools', items: [ 'Maximize', 'ShowBlocks' ] },
],
removePlugins: ['language'],
extraPlugins: "strinsert",
}}
/>
);
}
}
export { TextEditor };
After adding this when I am opening the text editor it shows me an error inside console::
Error::
ckeditor.js:98 GET https://cdn.ckeditor.com/4.15.1/standard-all/plugins/strinsert/plugin.js?t=KA9B
ckeditor.js:258 Uncaught Error: [CKEDITOR.resourceManager.load] Resource name "strinsert" was not found at "https://cdn.ckeditor.com/4.15.1/standard-all/plugins/strinsert/plugin.js?t=KA9B".
at window.CKEDITOR.window.CKEDITOR.dom.CKEDITOR.resourceManager.<anonymous> (ckeditor.js:258)
at n (ckeditor.js:253)
at Array.v (ckeditor.js:254)
at y (ckeditor.js:254)
at HTMLScriptElement.CKEDITOR.env.ie.g.$.onerror (ckeditor.js:255)
Please suggest how can I add "strinsert" custom plugin inside ckeditor4-react text editor.

How to use Kendo-ui grid for virtualization of remote data?

I'm using kendo-ui grid for AngularJs and want to activate virtualization of remote data functionality. For testing I have set pageSize: 5.
Below is description of virtualization of remote data from telerik site:
There are cases when you may need to operate with large amount of data
in the grid, and fetching and processing this data at once would
impose a performance penalty due to limited browser resources.
Luckily, the Kendo UI grid has a solution called data virtualization
that alleviates any slowdowns when operating with huge volumes of
data. When enabled via the scrollable->virtual configuration option,
it displays a vertical scrollbar for the grid content and renders only
the number of items set via the pageSize property of the grid data
source. After you drag the scrollbar and the pageSize is exceeded, it
makes automatic requests to retrieve and render the next set of grid
rows. Both local and remote data are supported with the grid
virtualization feature, whereas in this demo the records are obtained
from a remote endpoint.
Also I have set following:
HTML:
<div kendo-grid k-options="mainGridOptions" id="historyGrid" style="width: auto;"></div>
JS for grid:
var vm = $scope;
vm.viewMode = {
mainGridOptions: {
visible: true
}
};
vm.mainGridOptions = {
columns: [
// here columns
],
onRegisterApi: function (gridApi) {
vm.gridApi = gridApi;
},
dataSource: {
schema: {
model: {
fields: {
YearBalance: { type: 'number' },
Typezalezh: { type: 'string' },
License: { type: 'string' },
ObjectName: { type: 'string' },
ZalezhName: { type: 'string' },
PlastName: { type: 'string' },
Category: { type: 'string' },
Parameter: { type: 'string' },
LastVal: { type: 'string' },
Val: { type: 'string' },
Operation: { type: 'string' },
EndT: { type: 'date' }
}
}
},
pageSize: 5,
transport: {
read: function(e) {
dataservice.getImportResultReport().then(function(data) {
e.success(JSON.parse(data));
console.log(data);
});
}
}
},
serverPaging: true,
height: screen.height - 330,
minwidth : 1190,
batch: true,
scrollable: {
virtual: true
},
sortable: true,
serverSorting: true,
filterable: {
extra: false,
operators: {
string: {
// here filters
},
number: {
// here filters
},
date: {
// here filters
}
}
}
};
On telerik site (Official website), it says that nothing more needs to be done.
On scrolling, I should see a request to the server which in my case should be a dataservice.getImportResultReport() call. But this does't happen. This function is called only once and all data is returned.
May be it's occurring because I have not set type: "odata"? But I use data source of another type.
How to use this functionality?
Add k-scrollable directive as follows in your html that renders your kendo grid:
<div kendo-grid k-data-source="mainGridOptions" k-scrollable="{virtual:true}"></div>
Also you have to use k-data-source directive for your dataSource. Hope it helps.
Working demo plunkr

AngularJS Kendo UI grid with row filters behaviour

I am using Kendo UI Grid with row filters. i am facing filters options issue. I am using Filterbale.cell.template for filters to display kendo autoComplete.
Issue is as displayed in image autocomplete options are not updating on selecting of one of the filters.
Below is my html
<div ng-controller="VehiclesController" class="my-grid" >
<kendo-grid options="vehiclesGridOption">
</kendo-grid>
</div>
Below is my Controller
$scope.vehiclesGridOption = {
dataSource: {
schema: {
id: "_id",
model: {
fields: {
make: {type: "string"},
model: {type: "string"},
year: {type: "number"}
}
}
},
transport: {
read: function (e) {
vehicleService.vehicles().then(function (response) {
e.success(response);
console.log(response.length);
}).then(function () {
console.log("error happened");
})
}
},
pageSize: 12,
pageSizes: false,
},
sortable: {
mode: "multiple",
allowUnsort: true
},
filterable: {
mode: "row"
},
pageable: {
buttonCount: 5
},
columns: [
{
title: "",
template: '',
width: "3%" // ACTS AS SPACER
},
{
field: "make",
title: "Make",
filterable: {
cell: {
operator: "contains",
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "make",
dataValueField: "make",
valuePrimitive: true,
placeholder: "Make",
});
}
}
},
width: "29%",
}, {
field: "model",
filterable: {
cell: {
operator: "contains",
template: function (args) {
console.log(args);
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "model",
dataValueField: "model",
valuePrimitive: true,
placeholder: "Model",
});
}
}
},
title: "Model",
width: "29%",
}, {
field: "year",
title: "Year",
filterable: {
cell: {
template: function (args) {
args.element.kendoAutoComplete({
dataSource: args.dataSource,
dataTextField: "year",
dataValueField: "year",
placeholder: "Year",
suggest: true,
ignoreCase: true,
filter: "gte"
});
}
}
},
width: "29%",
},
{
field: "",
title: "Edit",
template: '<a class=\"k-link text-center grid-edit-btn vehicle-grid-edit-btn\" ui-sref="vehicleDetails({\'id\': \'#=_id #\' })"><span class=\"icon-editpencil icon-grid\"></span></a>',
width: "10%",
}],
};
Below is the Issue if user selects the Make in the first column filter then Model filter should display only selected make models like Honda (make)-> Accord , Civic ..etc but its displaying all unique values irrespective of model filter..
Kendo filter row uses the same dataSource from the grid component, just providing unique values. Since the autocomplete components are initialized when the grid dataSource is empty, they always show all the values.
You can manually filter based on current filter row values.
Firstly, add ids for your coresponding autocomplete components i.e. inside template functions:
args.element.attr('id', 'make');
//<...>
args.element.attr('id', 'model');
//<...>
args.element.attr('id', 'year');
Then add a data bound event to the grid (since autocomplete components do not fire change events when filters are cleared).
$scope.vehiclesGridOption = {
//...
dataBound : function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
});
}
}
Or if you also want to filter by "Year" column, it could go like this:
$scope.vehiclesGridOption = {
//...
dataBound: function(e) {
setTimeout(function() { //timeout is to make sure value() is already updated
var make = $('#make').data('kendoAutoComplete').value();
var model = $('#model').data('kendoAutoComplete').value();
if (make) {
$('#model').data('kendoAutoComplete').dataSource.filter({field: 'make', operator: 'eq', value: make });
} else {
$('#model').data('kendoAutoComplete').dataSource.filter({});
}
var yearFilter = {filters: [], logic: 'and'};
if (make) {
yearFilter.filters.push({field: 'make', operator: 'eq', value: make });
}
if (model) {
yearFilter.filters.push({field: 'model', operator: 'eq', value: model });
}
$('#year').data('kendoAutoComplete').dataSource.filter(yearFilter.filters.length ? yearFilter : null);
});
}
}

Resources