Difference between script filed and life cycle methods in Grapesjs? - javascript

I am new to Grapesjs, and i find the intro in Grapesjs doc website:
so if we have code like this:
editor.BlockManager.add('test-block', {
label: 'Test block',
attributes: {class: 'fa fa-text'},
content: {
script: "alert('Hi'); console.log('the element', this)",
// Add some style just to make the component visible
style: {
width: '100px',
height: '100px',
'background-color': 'red',
}
}
});
On the doc website it says:
If you check now the generated HTML coded by the editor (via Export button or editor.getHtml()), you might see something like this:
<div id="c764"></div>
<script>
var items = document.querySelectorAll('#c764');
for (var i = 0, len = items.length; i < len; i++) {
(function(){
// START component code
alert('Hi');
console.log('the element', this)
// END component code
}.bind(items[i]))();
}
</script>
It looks like all the stuff defined in script tag will be executed after the component mount, on the other way, considering Grapesjs provide view.init() and view.onRender() such life cycle methods, I was thinking we can probably achieve exactly the same effect using such life cycle methods.
So my question would be: what's difference between the script and component own life cycle methods?
BTW, I use React before, and i did most state initialization and data fetching in componentDidMount() such life cycle, so i personally could not get what could be the scenario for script in Grapesjs(Especially when i comparing those two libs.)?

As you should know Grapes uses backbone.js, which is pretty different to react.
Now, talking about how it works for grapesjs.
Lifecycle hooks will allow you to interact with model and editor instance during website building process.
Script will contain javascript your component needs to be useful in and outside the editor (Obviously, having limited (read-only) access to model properties).
Here you can see a very basic, and probably dummy example of both cases.
Setting listener on init: You'll probably won't need to alert changes in component attributes in resulting page...
Add animation class: script will run when render in editor, but also will run at published page, so you can see the animation out of grapes' editor.
const editor = grapesjs.init({
height: "100%",
container: "#gjs",
showOffsets: true,
fromElement: true,
noticeOnUnload: false,
storageManager: false,
canvas: {
styles: [
"https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css"
]
}
});
editor.DomComponents.addType("MagicBox", {
model: {
defaults: {
tagName: "div",
attributes: {
alert: ""
},
traits: ["alert"]
},
init() {
this.listenTo(this, "change:attributes:alert", this.handleChange);
},
handleChange(a) {
alert(this.get("attributes").alert);
}
}
});
const blockManager = editor.BlockManager;
blockManager.add("magic-box", {
label: "MagicBox",
content: {
type: "MagicBox",
tagName: "div",
style: {
width: "100px",
height: "100px",
background: "blue"
},
script: 'this.className+="animate__animated animate__bounce"'
},
category: "Basic",
attributes: {
title: "Magic Box"
}
});

Related

Dragging windows

I did some research on this and still can't find a good solution for it. I wrote my app in ExtJS 4.1 and when I run it on an iPod the dragging functionality is disabled by default (which is what I want), but if I write the same app in ExtJS 6.2 all windows can be draggable which causes issues of visibility of the app. With that being said, Does anyone know how to disable window dragging when using Tablets (iPod, iPad, etc.)? I'm using ExtJS 6.2
Here's my working code that works great for a single window, but I want a general solution that will stop ALL windows from being dragged.
var win = Ext.create('Ext.Window', {
title: "My Window",
width: 500,
modal: true,
layout: 'fit',
items: form,
buttons: [{
text: 'Close',
handler: function() {
win.hide();
}
}]
});
win.show();
if(Ext.os.deviceType === 'Tablet') {
win.dd.disable();
}
A "global solution" sounds like you want to use an override to apply one of the other answers globally to your application:
Ext.define('MyAppName.override.Window', {
override: 'Ext.window.Window',
initComponent: function() {
this.callParent(arguments);
if(Ext.os.deviceType === 'Tablet') {
this.dd.disable();
}
}
})
or
Ext.define('MyAppName.override.Window', {
override: 'Ext.window.Window',
initComponent: function() {
if(Ext.os.deviceType === 'Tablet') {
this.draggable = false;
}
this.callParent(arguments);
}
})
To make the override work, put it into the file app/override/Window.js and add a reference to your requires array in Application.js:
requires: [
'MyAppName.override.Window'
],
You are looking for Ext.os class.
More precisely Ext.os.is method, according to the docs it has all the values you would need.
I am not sure why you want to block only iPads and not tables in general. If you wan tablets than you can use if(Ext.os.deviceType === 'Tablet') {...}
Otherwise if(Ext.os.is.iPad) {...}.
UPDATE Solution:
If you want to force anything across all classes in the ExtJS you would use Ext.override.
So the solution would be to put at the beginning of the app this code:
if (Ext.os.deviceType === 'Tablet') {
Ext.override('Ext.Window', {
privates: {
initDraggable: function(){}
}
})
}
FYI You can check the Ext.Window source code. I had to override this method, the default value draggable: false doesn't work.
https://fiddle.sencha.com/#view/editor&fiddle/2iqi
To test it, just press F12 switch to table mode.
But this solution has 1 drawback:
If the target is a class declared using Ext.define, the override
method of that class is called
Which means this solution don't work when you use Ext.create('Ext.Window',{})
Solution for that would be to define our own Ext.Window class and than inside the app when you are using Ext.create('Ext.Window' you would use Ext.create('Fiddle.view.MyWindow', and when we have our own function already we don't need to use override but can put if directly into the class definition like this:
Ext.define('Fiddle.view.MyWindow', {
extend: 'Ext.Window',
alias: 'widget.mywindow',
draggable: (function(){
if (Ext.os.deviceType === 'Tablet') {
return false;
} else {
return true;
}
})()
});
https://fiddle.sencha.com/#view/editor&fiddle/2iqj
I don't know how to override it for Ext.create('Ext.Window' if you still insists on using it. One solution would be to re-write Ext.create or simply edit the framework source itself but I highly discourage from that.
Why you are not using draggable: false in window config
Here is some code in FIDDLE
var win = Ext.create('Fiddle.view.MyWindow', {
title: "My Window",
width: 500,
draggable: false,
modal: true,
layout: 'fit',
buttons: [{
text: 'Close',
handler: function() {
win.hide();
}
}]
});
win.show();

Replacing javascript Alerts with Kendo Notification

I'm wondering the best way to replace all my alert('error...') with kendo notifications, the easiest way.
so I can just do
myKendoAlert('my message', info); and I don't have to add a specific html div or span holder to each page.
currently I'm doing something like:
var popupNotification = $("#popupNotification").kendoNotification({
position: {
pinned: false,
bottom: 100,
right: 100
},
templates: [{
type: "info",
template: "<div>Test : #= myMessage #</div>"
}],
autoHideAfter: 0,
stacking: "up"
}).data("kendoNotification");
But I need to put this in a common javascript file with a function I can use on all pages. with, info, error, success... (and clear on success)
Just add a method to your namespace to do just that, and call it from where ever you need to.
Here is a sample that is similar to what I do, putting two methods, showSuccess and showError on the top level of the javascript namespace for my application (I use toastr, but same approach).
I have my app object on the window object, with two methods I can call from wherever.
http://jsbin.com/novena/1/edit
var notificationWidget = null;
function alert(message, type) {
if (notificationWidget == null) {
notificationWidget = $("#notification").kendoNotification({
button: true,
hideOnClick: true,
//appendTo: "#container",
//width: "30em",
position: {
pinned: true,
top: "5em",
left: null,
bottom: null,
right: 10
},
autoHideAfter: 8000
}).data("kendoNotification");
}
notificationWidget.show(message, type);
}

Proper way of adding stuff to senchas carousell in runtime

So how can I add stuff to carousell in sencha touch 2.x?
var c = Ext.create('Ext.Carousel', {
fullscreen: true,
defaults: {
styleHtmlContent: true
},
items: [
{
html : 'Item 1'
}]
});
If I want to, for example, push a form f to the carousell how can I do that?
I have already tried c.push(f) and c.add(f) but I can't see my form being added there.
The proper way of adding stuff into a container like Ext.Carousel is using the add() function. You can also define your carousel like this, if you want to just add all your stuff to it in runtime:
var c = Ext.create('Ext.Carousel', {
fullscreen: true,
defaults: {
styleHtmlContent: true
}
});
Now you can use the c.add(f) function. Also to remove the object f from the carousel or other container c use c.remove(f)

Javascript/ExtJS - get Codemirror Editor by textarea

Hello stackoverflow community,
i just built a Codemirror Editor into an ExtJSProject like so:
addCodeMirrorPanel: function() {
this.getAixmFormarea().add(Ext.widget({
xtype: 'textarea',
fieldLabel: 'AIXM',
autoScroll: true,
name: 'aixm',
id: 'codearea',
width: 800,
height: 300,
resizable: true,
resizeHandles: 's se e',
listeners: {
afterrender: function () {
var textarea = Ext.getCmp('codearea');
var codemirror = CodeMirror.fromTextArea(textarea.inputEl.dom,{
lineNumbers: true,
content: '',
matchBrackets: true,
electricChars:true,
autoClearEmptyLines: true,
extraKeys: {"Enter": "newlineAndIndentContinueComment"}
});
}
}
}));
}
Now what i want to do is access the codemirror editor from a different Controller function
and im not quite sure about how to do that.
no getinstance() , geteditorbyID() or similar methods are specified in the codemirror manual and i cant seem to access it from the now hidden textfield either.
Well why are you discarding the instance after you are creating it? Perhaps you could simply store it on the widget?
this.codeMirror = CodeMirror.fromTextArea(...);
I ran into a similar issue and was originally using the answer provided by plalx. However, if you are in need of creating instances of codemirror's dynamically this can get tricky.
I used the following code and created a method on the parent component to getValue(), setValue(), and getCodeMirror()
So in use you can get the codemirror instance similar to this:
var codeMirror = Ext.ComponentQuery.query('#parentFld')[0].getCodeMirror();
Here is the component code:
{
fieldLabel: 'Code Instance',
itemId: 'parentFld',
border: 1,
html: '<textarea></textarea>',
/* Overriding getValue function of the field to pull value from the codemirror text area*/
getValue: function (value) {
return this.getCodeMirror().getValue();
},
/*Overriding setValue function of the field to put the value in the code mirror window*/
setValue: function (value) {
this.getCodeMirror().setValue(value);
},
getCodeMirror: function () {
return this.getEl().query('.CodeMirror')[0].CodeMirror;
},
listeners: {
//on render of the component convert the textarea into a codemirror.
render: function () {
var codeMirror = CodeMirror.fromTextArea(this.getEl().down('textarea').dom, {
mode: {
name: "text/x-sql", globalVars: true
},
//theme: theme,
lineNumbers: true,
readOnly: false,
extraKeys: {"Ctrl-Space":"autocomplete"}
});
codeMirror.setSize(700, 370);
}
}
}

How to force a refresh on a Kendo UI Grid filled with remote data?

I have a Kendo UI Grid filled with info from a remote source and I want to force a refresh on the information displayed after a Kendo UI Window on my website is closed.
I tried this:
var grid = $("#usuariosGrid").data("kendoGrid");
grid.refresh();
But it didn't work, this is how I create the Kendo UI Grid:
var ds = new kendo.data.DataSource({
transport: {
read: {
url: root_url + "/usuario/index",
dataType: "json"
}
},
schema: {
data: "Response",
total: "Count"
},
serverPaging: false,
pageSize: 2
});
$("#usuariosGrid").kendoGrid({
pageable: {
refresh: true
},
columns: [
{ field: "UsuarioId", title: "ID", width: "100px" },
{ field: "Nombre", title: "Nombre", width: "100px" },
{ field: "ApellidoP", title: "Apellido Paterno", width: "100px" },
{ field: "ApellidoM", title: "Apellido Materno", width: "100px" },
{ command: [{ text: "Editar", click: editFunction }, { text: "Eliminar", click: deleteFunction }], title: " ", width: "200px" }
],
dataSource: ds
});
I looked at the documentation but didn't come across a method to do this.
On a side note, I've been wondering how to display a loading animation on the Kendo UI Grid while the data is being loaded into it, it is shown after it's been loaded and I'm clicking through the pages of the grid, but when there's no data, it looks collapsed and I would like to display a loading animation to make it look filled while the info is being loaded.
As #NicholasButtler suggests, use ds.read() for forcing a read. Depending on your DataSource definition, the result might be cached. Check this on enabling/disabling transport.read.cache.
For replacing the loading image redefine the class .k-loading-image. Example:
.k-loading-image {
background-image:url('http://24.media.tumblr.com/cfa55f70bbc5ce545eed804fa61a9d26/tumblr_mfpmmdCdWA1s1r5leo1_500.gif')
}
EDIT In order to guarantee that you have space enough for displaying the image add the following style definition:
#grid .k-grid-content {
min-height: 100px;
}
Fiddle example here : http://jsfiddle.net/OnaBai/nYYHk/1/
I had problems with the loading image not showing when loading remote data, but I noticed it was only on certain grids.
Turns out, if you configure the grid with: scrollable: false option, the loading image shows as expected. There's no need to have a min-height in the CSS and there's no need to have a scrollable grid if you're also paging.

Categories