What am I doing wrong with this plugin?
editor.model.schema.register('section', {
allowAttributes: ['class']
});
editor.model.schema.register('a', {
allowAttributes: ['class', 'href', 'target', 'download']
});
editor.model.change(writer => {
const section = writer.createElement('section', {
class: 'button'
});
const link = writer.createElement('a', {
href: 'https://dominio.com/file.pdf',
target: '_blank',
download: 'file.pdf'
});
writer.appendText('DOWNLOAD', link);
writer.insert(link, section);
editor.model.insertContent(section, editor.model.document.selection);
});
The result is being:
<p>DOWNLAOD</p>
But it should be:
<section class="button">DOWNLOAD</section>
Does anyone know where I'm going wrong in creating this plugin on ckeditor 5?
I couldn't resolve it as I would like, but I did it like this:
editor.model.change(writer => {
const link = writer.createText('DOWNLOAD', {
linkHref: 'https://file_link'
});
editor.model.insertContent(link, editor.model.document.selection);
});
Related
i have been exploring back4app parse server. i am tiered of finding documentation for pdf files. I am trying to generate some pdf files on back4app parse server from its cloud function.i do not see any documentation for it. will some one guide me to find it and little enlightment will be highly appreciated.
edit:
pdf creator library out there ask for output path but in back4app we don't have early access to path. we create new file passing it data and then save it to object. how do we achieve the order.
I some how managed get it done, thank you #Davi macedo. but there is some problem, i created pdf locally(root) cloud code,deleting it each time is envitable . this could be problem for more requests.
can someone improve little bit. would be great.
Here is my code.
I have used pdf-creator-node for creating pdf.
var pdf = require("pdf-creator-node");
var fs = require("fs")
var path = require('path')
const pdf2base64 = require('pdf-to-base64');
Parse.Cloud.define("pdf", async (req) => {
//creating pdf
// var html = fs.readFileSync("template.html", "utf8");
var html = fs.readFileSync(path.resolve(__dirname, 'template.html'), {
encoding: 'utf-8' });
var options = {
format: "A3",
orientation: "portrait",
border: "10mm",
header: {
height: "45mm",
contents: '<div style="text-align: center;">Author: Shyam Hajare</div>'
},
footer: {
height: "28mm",
contents: {
first: 'Cover page',
2: 'Second page', // Any page number is working. 1-based index
default: '<span style="color: #444;">{{page}}</span>/<span>{{pages}}</span>', // fallback value
last: 'Last Page'
}
}
};
var users = [
{
name: "Shyam",
age: "26",
},
{
name: "Navjot",
age: "26",
},
{
name: "Vitthal",
age: "26",
},
];
var document = {
html: html,
data: {
users: users,
},
path: path.resolve(__dirname, './pdfs', 'my_file.pdf'),//using path is necessary
type: "",
};
return pdf
.create(document, options)
.then((res) => {
return pdf2base64(path.resolve(__dirname, "/usr/src/app/data/cloud /pdfs/my_file.pdf")) //this path /usr/src/app/data/cloud/pdfs still mystery to me.
.then(
(response) => {
// console.log(response); //cGF0aC90by9maWxlLmpwZw==
const saveFiles = async () => {
//creating file
const parseFile = new Parse.File('pdfFile.pdf',{base64:response});
// console.log(parseFile)
//saving file
const responseFile = await parseFile.save();
const Document = Parse.Object.extend('Document');
const document = new Document();
//saving it to object.
document.set('document', responseFile);
await document.save();
}
saveFiles();
}
)
.catch(
(error) => {
console.log(error); //Exepection error....
}
)
console.log(res);
})
.catch((error) => {
console.error(error);
});
});
After upgrading to react-navigation 3.3.2 the tabBarOnPress no longer fires. Code snippet below. Any ideas?
const Tabs = createBottomTabNavigator(
{
HomeStack,
WallStack,
MemeStack,
},
{
navigationOptions: ({navigation}) => ({
tabBarOnPress: () => {
console.log('tab pressed');
}
})
}
);
export default DrawerNav = createDrawerNavigator({
Tabs: Tabs
},{
drawerBackgroundColor: Colors.grayDark,
contentComponent: Sidebar
})
tabBarOnPress is working, but I'm using it like this. You need to pass it as a property of each stack. (don't forget to call the defaultHandler to keep the default behavior:
const DashboardStack = createStackNavigator(
{
Dashboard,
}
);
DashboardStack.navigationOptions = {
tabBarOnPress({ navigation, defaultHandler }) {
// do something
defaultHandler();
},
};
const ProfileStack = createStackNavigator(
{
Profile,
AccountInfo,
Membership,
Browser,
ConnectedAccounts,
}
);
ProfileStack.navigationOptions = {
tabBarOnPress({ navigation, defaultHandler }) {
// do something
defaultHandler();
},
};
const SpendingStack = createStackNavigator(
{
Budget,
Transactions,
}
);
SpendingStack.navigationOptions = {
tabBarOnPress({ navigation, defaultHandler }) {
// do something
defaultHandler();
},
};
export default createBottomTabNavigator(
{
SpendingStack,
DashboardStack,
ProfileStack,
}
);
I am a bit confused using VueJS2. I added a few variables to the data container for sending it to my API. That works fine but Vue is throwing me a warning/error message which I don't know how to solve:
Avoid adding reactive properties to a Vue instance or its root $data
at runtime - declare it upfront in the data option.
var app = new Vue({
el: '#app',
data: {
incidentReference: '',
streetName: '',
latitude: '',
longitude: '',
featureTypeId: 1,
archived: 0
},
computed: {
href() {
return '#' + this.name.toLowerCase().replace(/ /g, '-');
}
},
mounted: function () {
this.getIncidents();
},
methods: {
onSubmit() {
axios.post('/api/v1/incidents', this.$data)
.then(response => alert('Success'))
.catch(error => {
console.log(error.response);
})
},
getIncidents: function() {
console.log('getIncidents');
var self = this;
axios.get('/api/v1/incidents').then(function(response) {
// set data on vm
console.log(response.data);
var incidentsReceived = response.data.data.map(function (incident) {
return incident;
});
Vue.set(self, 'incidents', incidentsReceived);
});
}
}
});
You're creating a new reactive property on the response of your API
Vue.set(self, 'incidents', incidentsReceived);
Not sure if you misspelled property's name or forget to create that property. Just use an existing property on you data section
Vue.set(self, 'incidentReference', incidentsReceived); //change property name
or
data: {
incidents: null, //or create this property
},
In my case during unit testing using Jest, I was setting selected but didn't have on component so got this error.
wrapper.setData({
selected: recipients,
});
So created the property on component and then it's working fine.
In the context of Jest & Vue Test Utils consider declaring data in component:
const Component = {
// ..
data() { return { abc: 'abc'; } }
};
const wrapper = mount(Component, { /*..*/ });
instead of
const Component = { /*..*/ };
const wrapper = mount(Component, { /*..*/ });
wrapper.setData({ abc: 'abc' });
await wrapper.vm.$nextTick();
var ContactManager = new Marionette.Application();
ContactManager.addRegions({
mainRegion: "#main-region",
child:"#child2"
});
Ar = Backbone.Model.extend({});
Se = Backbone.Model.extend({});
Articlescollection = new Ar({ product_id: "104", title: "Test title"});
SelectedsCollection = new Se({ product_id: "71", title: "Test title"});
ContactManager.StaticView = Marionette.ItemView.extend({
template: tpl2,
tagName: "div",
model:Articlescollection,
modelEvents: {
'change': 'fieldsChanged'
},
fieldsChanged:function(){
console.log('dddd')
},
initialize: function () {
this.model.on('change', this.render);
}
});
ContactManager.StaticView2 = Marionette.ItemView.extend({
template: tpl2,
tagName: "div",
model:SelectedsCollection
});
var MyLayout = Backbone.Marionette.LayoutView.extend({
template: tpl3,
regions: {
menu: "#menu",
content: "#content"
}
});
ContactManager.on("start", function() {
// ContactManager.mainRegion.show( new MyLayout )
var layout = new MyLayout
ContactManager.mainRegion.show( layout )
layout.menu.show(new ContactManager.StaticView());
layout.content.show(new ContactManager.StaticView2())
Articlescollection.set("product_id", 24)
//init fieldsChanged trigger for change model
})
ContactManager.start();
What differences between modelEvents and this.model.on ?
they both initizlized when model was change but
modelEvents: {
'change': this.render
},
throw exception Uncaught TypeError: Cannot read property 'split' of undefined
modelEvents is the same as this.listenTo(this.model, { 'change': 'fieldsChanged' }); It is just sugar so you don't have to add that to initialize. You should probably never use this.model.on inside a view. That would not get cleaned up automatically like this.listenTo would. Other than this.on I don't think on should be used in general as listenTo is much safer.
The other major difference here is that:
var model = this.model;
var view = this;
this.model.on('change', function() {
this === model; // true
this === view; //false
});
The only reason this would work with render is because render is forcibly bound to the view by marionette. Any other function would have a different scope. You can change the scope by passing it as the 3rd variable of on, but again then you need to this.model.off in onBeforeDestroy
If you want to call render from modelEvents you have a few options:
modelEvents: {
'change': 'render'
}
//or
modelEvents: function() {
return {
'change': this.render
};
}
// or
modelEvents: {
'change': function() { this.render(); }
}
In my app, i have the regions as header,content,footer - in which on the login page, I don't want to use the header, and footer. for that, on onRender i remove the regions what i don't want to be.
But I am getting an error saying: Cannot read property 'empty' of undefined.
here is my template : (i use jade )
div#wrapper
script(type='text/template', id="appTemplate")
div#header
div#content
div#footer
script(type='text/template', id="loginTemplate")
div this is login template
here is my layout.js:
socialApp.AppLayout = Backbone.Marionette.LayoutView.extend({
el:'#wrapper',
template:'#appTemplate',
regions: {
header : '#header',
content : '#content',
footer : '#footer'
},
onRender : function () {
this.removeRegion("header", "#header"); //i am removing header alone here.
}
});
here is my controller.js
socialApp.loginController = Marionette.Controller.extend({
_initialize:function(){
this.loginView = new loginView({model:new loginModel});
this.layout.onRender(); //calling onRender from here...
this.layout.content.show(this.loginView);
}
});
But it's all not working. any one help me the correct way please?
You should never call methods that are prefixed with on manually. Those are there for your code to react to given events, in this case that the view’s render method was invoked.
I would suggest that you instead of trying to remove and then later re-add regions, you create two different layouts. Then when your router hits the login route, you render LoginLayout into your App’s root region, and for other routes, the ‘normal’ layout. Here’s how I solved something similar:
app.js:
var App = new Marionette.Application;
App.addRegions({ root: '#acme' });
// Instantiate User model
App.addInitializer(function()
{
this.user = new UserModel;
});
// Render App layout
App.addInitializer(function()
{
this.layout = this.user.get('id') ? new ContentLayoutView({ identifier: 'content' }) : new UserLayoutView({ identifier: 'user' });
this.root.show(this.layout);
// And let the routers decide what goes in the content region of each layout
this.router = {
content: new ContentRouter,
user: new UserRouter
};
});
layout/content.js
var ContentLayout = Marionette.LayoutView.extend(
{
identifier: 'content',
template: ContentLayoutTemplate,
regions: {
content: '[data-region="content"]',
panelLeft: '[data-region="panel-left"]',
panelRight: '[data-region="panel-right"]'
},
initialize: function()
{
this.content.once('show', function(view)
{
this.panelLeft.show(new PanelLeftView);
this.panelRight.show(new PanelRightView);
}.bind(this));
}
});
layout/user.js
var UserLayout = Marionette.LayoutView.extend(
{
identifier: 'user',
template: UserLayoutTemplate,
regions: {
content: '[data-region="content"]'
}
});
router/content.js
var ContentRouter = Marionette.AppRouter.extend(
{
routes: {
'(/)': '...'
},
createLayout: function(callback)
{
if(App.root.currentView.options.identifier != 'content')
{
var layout = new ContentLayoutView({ identifier: 'content' });
this.region = layout.content;
this.listenTo(layout, 'show', callback);
App.root.show(layout);
}
else
{
this.region = App.root.currentView.content;
callback();
}
},
execute: function(callback, args)
{
if(App.user.get('id'))
{
this.createLayout(function()
{
callback.apply(this, args);
}.bind(this));
}
else
App.router.user.navigate('login', true);
}
});
router/user.js
var UserRouter = Marionette.AppRouter.extend(
{
routes: {
'login(/)': 'showLogin',
'logout(/)': 'showLogout'
},
createLayout: function(callback)
{
if(App.root.currentView.options.identifier != 'user')
{
var layout = new UserLayoutView({ identifier: 'user' });
this.region = layout.content;
this.listenTo(layout, 'show', callback);
App.root.show(layout);
}
else
{
this.region = App.root.currentView.content;
callback();
}
},
execute: function(callback, args)
{
this.createLayout(function()
{
callback.apply(this, args);
}.bind(this));
},
showLogin: function()
{
var LoginView = require('view/detail/login');
this.region.show(new LoginView);
},
showLogout: function()
{
var LogoutView = require('view/detail/logout');
this.region.show(new LogoutView);
}
});