ckeditor5 custom upload adapter - custom-adapter

When I try to select an image from the tool 'Insert image' the value of the loader is undefined and the image don't upload.
I've reading the documentation buy I can't find why my images don't move to my local folder 'uploads'.
Here is the code, it's mostly copied from the documentation, but the image don't move.
If I write http://localhost/uploads in the browser, the path is correct.
<html>
<head>
<script src="https://cdn.ckeditor.com/ckeditor5/16.0.0/classic/ckeditor.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<div id="editor"></div>
</body>
</html>
<script>
class MyUploadAdapter {
constructor( loader ) {
// The file loader instance to use during the upload.
this.loader = loader;
}
// Starts the upload process.
upload() {
return this.loader.file
.then( file => new Promise( ( resolve, reject ) => {
this._initRequest();
this._initListeners( resolve, reject, file );
this._sendRequest( file );
} ) );
}
// Aborts the upload process.
abort() {
if ( this.xhr ) {
this.xhr.abort();
}
}
// Initializes the XMLHttpRequest object using the URL passed to the constructor.
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
xhr.open( 'POST', 'http://localhost/uploads', true );
xhr.responseType = 'json';
}
// Initializes XMLHttpRequest listeners.
_initListeners( resolve, reject, file ) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = `Couldn't upload file: ${ file.name }.`;
xhr.addEventListener( 'error', () => reject( genericErrorText ) );
xhr.addEventListener( 'abort', () => reject() );
xhr.addEventListener( 'load', () => {
const response = xhr.response;
if ( !response || response.error ) {
return reject( response && response.error ? response.error.message : genericErrorText );
}
resolve( {
default: response.url
} );
} );
if ( xhr.upload ) {
xhr.upload.addEventListener( 'progress', evt => {
if ( evt.lengthComputable ) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
} );
}
}
_sendRequest( file ) {
const data = new FormData();
data.append( 'upload', file );
this.xhr.send( data );
}
}
function MyCustomUploadAdapterPlugin( editor ) {
editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
// Configure the URL to the upload script in your back-end here!
return new MyUploadAdapter( loader );
};
}
ClassicEditor
.create( document.querySelector( '#editor' ), {
extraPlugins: [ MyCustomUploadAdapterPlugin ]
} );
</script>

Related

How to access request data in layouts and pages in Qwik City

I'm creating an application Qwik and Qwik City.
I want to show something in my layout, only if it's the home page.
This is my layout.jsx:
const Layout = component$((props) => {
// console.log(props); // I don't see anything related to request
const isHomePage = true; // how can I know I'm inside the home page?
return <>
{isHomePage && <TopBar />}
</>
})
import { component$, Slot } from "#builder.io/qwik";
import { loader$, useLocation } from "#builder.io/qwik-city";
export const useUser = loader$(async ({ fail }) => {
try {
const res = await fetch("https://api.github.com/users/harshmangalam");
const user = await res.json();
return {
user,
};
} catch (error) {
return fail(500, {
error: "Something went wrong",
});
}
});
export default component$(() => {
const user = useUser();
const {
url: { pathname },
} = useLocation();
const isHomePage = pathname === "/";
return (
<div>
{isHomePage && <pre>{JSON.stringify(user.value, null, 4)}</pre>}
<Slot />
</div>
);
});

How to print image with PDF file in react native

I'm building a mobile application that will be able to print and generate PDF file both android and ios. I am having issues with adding image to it or printing image along with it. When I tried printing or generating PDF, what I only see is the ALT of the image. Please any help on how to go about it?
const copyFromAssets = async (asset) => {
try {
await Asset.loadAsync(asset);
const { localUri } = Asset.fromModule(asset);
return localUri;
} catch (error) {
console.log(error);
throw err;
}
};
const processLocalImageIOS = async (imageUri) => {
try {
const uriParts = imageUri.split(".");
const formatPart = uriParts[uriParts.length - 1];
let format;
if (formatPart.includes("png")) {
format = "png";
} else if (formatPart.includes("jpg") || formatPart.includes("jpeg")) {
format = "jpeg";
}
const { base64 } = await ImageManipulator.manipulateAsync(
imageUri,
[],
{ format: format || "png", base64: true }
);
return `data:image/${format};base64,${base64}`;
} catch (error) {
console.log(error);
throw error
}
};
const htmlContent = async () => {
try {
const asset = require('../../assets/images/unboard3.jpg');
let src = await copyFromAssets(asset);
if(Platform.OS === 'ios') {
src = await processLocalImageIOS(src);
}
return src;
} catch (error) {
console.log(error);
}
}
const createPDF = async (html) => {
try {
const {uri} = await Print.printToFileAsync(html);
Print.printAsync({ uri });
// this.setState({callPrint: false});
} catch(err) {
console.error(err);
// this.setState({callPrint: false});
}
};
const html = `
<html>
<body>
<div class='title-container'>
<img src="${htmlContent()}" alt="Logo" />
</div>
</body>
</html>`;

React native image crop picker network issue .... on api hit with axios

Ios working fine
Android = network issue
I am stuck from so many days
RN version = 0.63.4
Rn crop picker version = 0.36.1
From R&D
I did all sloution like
upgarde flipper version
comment flipper line = android/app/debug/flipeerfile
Here i am attatching code of axios , image uploading file
axios code =
// import axios from "axios";
// import { SiteUrl } from '../config/Setting';
// var instance = axios.create({
// baseURL: 'http://192.168.1.90:3000/api/v1/user-service/users/',
// timeout: 60000,
// headers: {
// 'Content-Type': 'application/json',
// 'Access-Control-Allow-Origin': '*',
// 'Access-Control-Allow-Headers': '*',
// },
// });
// instance.interceptors.request.use(function (config) {
// console.log('config is ',config)
// return config;
// }, function (error) {
// return error;
// });
// instance.interceptors.response.use(function (response) {
// // console.log('response of axios',response)
// return response;
// }, function (error) {
// console.log('error of axios',error)
// return error;
// })
// export default instance;
import AsyncStorage from '#react-native-async-storage/async-storage';
import axios from 'axios';
import {SiteUrl} from '../config/Setting';
function parseError(messages) {
// error
// console.log('message',messages)
if (messages) {
if (messages instanceof Array) {
return Promise.reject({messages: messages});
} else {
return Promise.reject({messages: [messages]});
}
} else {
return Promise.reject({messages: ['エラーが発生しました']});
}
}
/**
* parse response
*/
function parseBody(response) {
// if (response.status === 200 && response.data.status.code === 200) { // - if use custom status code
// if (response.status === 200) {
return response;
// return response.data.result
// } else {
// console.log('message',response)
// return this.parseError(response.data)
// }
}
/**
* axios instance
*/
let instance = axios.create({
baseURL: 'http://14.98.110.243:3000/api/v1/user-service/users/',
paramsSerializer: function (params) {
return qs.stringify(params, {indices: false});
},
});
// request header
instance.interceptors.request.use(
async config => {
console.log('config is = ', config);
// Do something before request is sent
let apiToken = '';
apiToken = await AsyncStorage.getItem('apiToken');
console.log('apiToken', apiToken);
config.headers = {
Authorization: `Bearer ${JSON.parse(apiToken)}`,
'Content-Type': 'multipart/form-data',
};
return config;
},
error => {
return Promise.reject(error);
},
);
// response parse
instance.interceptors.response.use(
response => {
return parseBody(response);
},
error => {
// console.warn('Error status', error.response.status)
// return Promise.reject(error)
if (error.response) {
return parseError(error.response.data);
} else {
return Promise.reject(error);
}
},
);
export default instance;
Here is file code =
i am using hooks ... and i want to store multiple image in array with path
const [images, setImages] = useState([]);
const image = await ImagePicker.openPicker({
height: 385,
maxFiles: 6,
minFiles: 3,
mediaType: 'photo',
multiple: true,
width: 1000,
}).then(image => {
console.log('imahge', image);
let images = [];
images = images;
image.forEach((ele, i) => {
images.push(ele.path);
});
setImages(images);
console.log('all', images);
});
} catch (error) {
console.log('Error:', error);
}
```
not an expert, but where are you calling the method to upload the image. I had these issue of "Network Error" using Fetch and solved it using a Form Data object. Here's my code:
ImagePicker.openPicker({
multiple: true,
forceJpg: true,
maxFiles: 5,
compressImageQuality: 0.5,
mediaType: 'photo'
})
.then(images =>{
//map of around the pictures and return a form data that will be passed to whole.js
images.map((item, index) => {
this.setState({numberImages: this.state.numberImages + 1})
this.state.formData.append("photo", {
uri: item.path,
type: "image/jpeg",
name: `pickedImage-${index}.jpg`
})
});
});
finally i got an answer actually my backend team use a package that want mime type also in image object ...
so when i send that it working fine ...
for eg =>
this.state.formData.append("photo", { uri: item.path, mime:"image/jpeg", type: "image/jpeg", name: `pickedImage-${index}.jpg` })

VueJS CKeditor5 upload images

Having trouble with uploading images using CKeditor5 in Vuejs.
First having tried Simple upload Adapter which gave me the following error:
Reason: CKEditorError: ckeditor-duplicated-modules: Some CKEditor 5 modules are duplicated. Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-ckeditor-duplicated-modules
I tried making a upload adapter. As a uploadadapter I took the example and modified the url. The uploadadapter.js file looks like the following:
export default class UploadAdapter {
constructor( loader ) {
// The file loader instance to use during the upload.
this.loader = loader;
}
// Starts the upload process.
upload() {
return this.loader.file
.then( file => new Promise( ( resolve, reject ) => {
this._initRequest();
this._initListeners( resolve, reject, file );
this._sendRequest( file );
} ) );
}
// Aborts the upload process.
abort() {
if ( this.xhr ) {
this.xhr.abort();
}
}
// Initializes the XMLHttpRequest object using the URL passed to the constructor.
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
xhr.open( 'POST', '<url here>', true );
xhr.responseType = 'json';
}
// Initializes XMLHttpRequest listeners.
_initListeners( resolve, reject, file ) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = `Couldn't upload file: ${ file.name }.`;
xhr.addEventListener( 'error', () => reject( genericErrorText ) );
xhr.addEventListener( 'abort', () => reject() );
xhr.addEventListener( 'load', () => {
const response = xhr.response;
if ( !response || response.error ) {
return reject( response && response.error ? response.error.message : genericErrorText );
}
resolve( {
default: response.url
} );
} );
if ( xhr.upload ) {
xhr.upload.addEventListener( 'progress', evt => {
if ( evt.lengthComputable ) {
loader.uploadTotal = evt.total;
loader.uploaded = evt.loaded;
}
} );
}
}
// Prepares the data and sends the request.
_sendRequest( file ) {
// Prepare the form data.
const data = new FormData();
data.append( 'upload', file );
// Send the request.
this.xhr.send( data );
}
}
The Vue component:
<template>
<form #submit.prevent="store">
<ckeditor
:editor="editor"
v-model="form.content"
:error-messages="errors.content"
:config="editorConfig"
/>
</form>
</template>
<script>
import CKEditor from '#ckeditor/ckeditor5-vue';
import ClassicEditor from '#ckeditor/ckeditor5-build-classic';
import UploadAdapter from '../../UploadAdapter';
export default {
data()
{
return {
form: {
content: null,
},
editor: ClassicEditor,
editorConfig: {
toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', '|', 'insertTable', '|', 'imageUpload', 'mediaEmbed', '|', 'undo', 'redo' ],
table: {
toolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ]
},
extraPlugin: [this.uploader],
language: 'nl',
},
}
},
methods: {
store()
{
// Some code
},
uploader(editor)
{
editor.plugins.get( 'FileRepository' ).createUploadAdapter = ( loader ) => {
return new UploadAdapter( loader );
};
},
},
components: {
ckeditor: CKEditor.component
}
}
</script>
However each time when trying to upload a file the following warning is returned:
filerepository-no-upload-adapter: Upload adapter is not defined. Read more: https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-filerepository-no-upload-adapter
Have looked at the url but it just sends me in circles thus making no progress. What I'm looking for is an example that at least sends a file to the server without errors/ warnings. If the uploadadapter can be scraped and something else except CKfinder can be used that's fine. For now I guess the problem is most likely to be in the Vue component.
use extraPlugins instead of extraPlugin.
moving uploader function to outside of vue component and then using it directly as
extraPlugin: [uploader]
worked for me.

Too many requests when controlling spinner show/hide from axois interceptors

I have an SPA written in Vue (Webpack) where I want to control the visibility of a spinner based on whether or not the app is currently handling an HTTP request or a response.
Following some tutorials, I came up with the event bus scheme and did this:
Created eventBus.js:
import Vue from 'vue';
export const eventBus = new Vue();
I'm setting my axios interceptors in the created() hook of App.vue. Here's what the necessary functions look like in that component:
data() {
return {
showLoader: false
};
},
created(){
this.setAxiosInterceptors();
// some code removed //
}
},
mounted() {
eventBus.$on('show-loader', () => {
this.showLoader = true;
});
eventBus.$on('hide-loader', () => {
this.showLoader = false;
});
},
methods: {
setAxiosInterceptors() {
var tokenCookieName = this.$store.getters.getCookieNames.apiToken;
var cookieDefaultValue = this.$store.getters.getCookieDefaultValue;
// token expired middleware
this.axios.interceptors.response.use(response => {
var data = response.data;
if(data.info.api_token) {
this.$cookie.set(tokenCookieName, data.info.api_token);
}
if(data.status == 'error' && data.info.login_failed) {
this.$cookie.set(tokenCookieName, cookieDefaultValue);
window.location = '/'; // not possible to use Vue router here
}
eventBus.$emit('hide-loader');
return response;
},
error => {
eventBus.$emit('hide-loader');
console.log('Response interception failed!');
return Promise.reject(error);
});
// attach API token middleware
this.axios.interceptors.request.use(config => {
var apiToken = this.$cookie.get(tokenCookieName);
if (!apiToken) {
apiToken = cookieDefaultValue;
}
config.headers.Authorization = 'Bearer ' + apiToken;
eventBus.$emit('show-loader');
return config;
},
error => {
eventBus.$emit('hide-loader');
console.log('Request interception failed!');
return Promise.reject(error);
}
);
}
}
Please ignore some of the code that isn't relevant to the problem, but I wanted to show how things are set up. Problem is, as soon as I visit my home page, the app keep making the startup GET requests over and over, until my server returns a 429 error.
Interestingly, in my eventBus.$on handlers, if I just do a console.log, this behavior doesn't appear (of course, the spinner doesn't work as well) but as soon as I change a variable or call a vuex action, this infinite reloading starts.
Any clue?
In the main.js file
Vue.prototype.$axios = axios.create(
{
headers:
{
'Content-Type': 'application/json',
},
baseURL: process.env.API_URL
}
);
Vue.prototype.$axios.interceptors.request.use(
config =>
{
eventBus.$emit('show_spin');
let token = getTokenID();
if(token && token.length) config.headers['Authorization'] = token;
return config;
},
error =>
{
eventBus.$emit('hide_spin');
if (error.status === 401) VueRouter.push('/login');
else throw error;
}
);
Vue.prototype.$axios.interceptors.response.use(
response =>
{
eventBus.$emit('hide_spin');
return response;
},
error =>
{
eventBus.$emit('hide_spin');
return new Promise(function(resolve,reject)
{
if (error.config && error.response && error.response.status === 401 && !error.config.__isRetry)
{
myVue.refreshToken(function()
{
error.config.__isRetry = true;
error.config.headers['Authorization'] = getTokenID();
myVue.$axios(error.config).then(resolve,reject);
},function(flag) // true = invalid session, false = something else
{
if(process.env.NODE_ENV === 'development') console.log('Could not refresh token');
if(getUserID()) myVue.showFailed('Could not refresh the Authorization Token');
reject(flag);
});
}
else throw error;
});
}
);
let myVue = new Vue(
{
el: '#app',
data: function()
{
return {
spin_visible: 0, // dynamically show/hide spinner
};
},
created: function()
{
eventBus.$on('show_spin', this.showSpin);
eventBus.$on('hide_spin', this.hideSpin);
},
methods:
{
showSpin: function()
{
this.spin_visible++;
},
hideSpin: function()
{
if(this.spin_visible>0) this.spin_visible--;
},
....
and then in App.vue
<template>
<router-view/>
<div class="spinner" v-show="$root.spin_visible">
<!-- define your spinner here -->
</div>
</template>