How to send external data to OnlyOffice plugin - asp.net

I am developing onlyoffice plugin, which need to consume data (like reportid, session details that will be used to load data from server) from launching application.
structure of page come out like:
launching page (editor.aspx)
-- iframe 1 to load editor
-- -- ifram 2 to load plugin
Here i want to access data from editor.aspx into iframe 2 (javascript)
I tried using queryString like window.parent.location.search but it only can traverse till iframe 1, but not main aspx page. As i don't have control on what loads in iframe 1 it didn't work.
Also i tried with cookies and localStorage but none worked out.
Please guide..

launching page (editor.aspx) -- iframe 1 to load editor -- -- ifram 2
to load plugin. Here i want to access data from editor.aspx into iframe
2 (javascript)
There is no way to get direct access to the iframe with editor, the only way to work with it is using document server plugins

Actually there is a way... Having spent a LOT of time analysing what is going on... finally found a nice way to exchange configs between the TOP frame and PLUGIN frame with just a few lines of code leveraging the onlyoffice API - without any hacks :)
Editor Config object:
config: {
"width" : "100%",
"height" : "100%",
"type" : "desktop",
"documentType": "text",
"token" : "{{token}}",
"document" : {
"title" : "{{document.name}}",
"url" : "{{downloadUrl}}",
...
events: {
'onReady': <application ready callback>, // deprecated
...
'onInfo': function ( data ) {
if ( data && data.data && data.data.getConfig ) {
docEditor.serviceCommand ( 'getConfig', config.document );
}
}
}
}
var docEditor = new DocsAPI.DocEditor("placeholder", config);
onInfo event will receive the request from your plugin.
Need to check the event data has getConfig attribute.
If it does, send back the config to the plugin.
Within your plugin's index.html add an inline script tag with this content:
// config ref
var config;
// Get ready to receive the response from TOP
window.parent.Common.Gateway.on ( 'internalcommand', ( data ) => {
if ( data.command === 'getConfig' ) {
config = data.data;
}
} );
// Send custom config request to TOP
window.parent.Common.Gateway.sendInfo ( { getConfig: true } );
It subscribes to the internalcommand Gateway events which will be called by TOP, then kick in the communication process by calling the sendInfo command. Because the editor and your plugins (most likely) will be hosted on the same domain, you can access it via the window.parent ref.
This will download the config.document configuration object and store it in the plugins local config variable automatically - when you click on the plugin in the toolbar.

Related

Nextjs export clear "out" folder

I'm working with nextjs and this example https://github.com/zeit/next.js/tree/master/examples/with-static-export
in next.config.js i have code:
module.exports = {
async exportPathMap(defaultPathMap, { dev, dir, outDir, distDir, buildId, incremental }) {
// we fetch our list of posts, this allow us to dynamically generate the exported pages
const response = await fetch(
'https://jsonplaceholder.typicode.com/posts?_limit=3'
)
const postList = await response.json()
// tranform the list of posts into a map of pages with the pathname `/post/:id`
const pages = postList.reduce(
(pages, post) =>
Object.assign({}, pages, {
[`/post/${post.id}`]: { page: '/post/[id]' },
}),
{}
)
// combine the map of post pages with the home
return Object.assign({}, pages, {
'/': { page: '/' },
})
},
}
Its fetch 3 posts and generate files - [id].html - its great!
But now i need to fetch new post and build page only for this new post but commad next export remove all files from out and create only one post.
What i need to do to keep old post and add new one on next export?
Example:
First next export with request for 3 posts from api
generate 3 post in folder "out"
change api url and run next export for 1 new post
summary i have 3 old post pages and 1 new in my "out" directory
How to do that?
Next can't do this out of the box, but you can set it up to do so. First, you'll need a system (database) of which pages have already been built. Second, you'll need some method of communicating with that database (api) to ask which pages should be built (eg, send over a list of pages and the api responds telling you which ones have not yet bene built). Then, tell your exportPathMap which pages to build. And finally, move your built pages out of out and into a new final/public directory.
By default, Next will build/export anything in the pages directory plus anything you set in exportPathMap, and put all of those in the out directory. You can override what it builds by passing a custom exportPathMap, and how you handle what goes into the out directory is up to you, so you can move those files to a different actual public directory and merge them with the old files.

How to save a file -in a folder- using FileSystem and CollectionFS ? (yeah, really.)

I think I'm missing something. I have read a lot of posts/examples and I can't save images on my system (I work locally).
What is my goal ?
I'm trying to save a file submitted by the user in a folder (server-side). Does it sound easy ? Maybe.
What's the issue ?
Short answer : I can't figure out how to save the file in my folder.
Do you want more information ?
The story of a file upload
I have read that to use the path parameter like new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" }) , I have to declare my collection server-side. But when I call Avatars.insert() (Avatars is the name of my collection), it seems like it doesn't exists. This makes sense because this collection exists only on the server.
So I've tried to declare the collection both server-side and client-side (I've read some examples about that) and that works ! The file is correctly added to MongoDB, but my folder is still empty (I'm not sure but I think this is because Avatars.insert() is called client-side so the collection used is the client-side one, the one which cannot take path parameter).
But no problem ! I've created 2 Meteor methods (one client-side and one server-side) called "updateAvatarFile". With this "trick", I'm able to do Meteor.call("updateAvatarFile", field.files[0]), which calls both server-side and client-side methods. So I can do some UI stuff in the client-side one and upload the file in the other. But I can't pass the file as a parameter.
field.files[0] contains the file client-side but server-side it's an empty object. My question is : How can I upload a file ?
I can't do it client-side (because I can't use path parameter) but I can pass the file to the server. I'm sure that I'm missing something but I can't figure what.
Here is how I go :
// /client/views/templates/settings.js
Template.settings.events({
'submit #updateAvatar': function (e, template) {
e.preventDefault();
const field = document.getElementsByName('avatar')[0];
Meteor.call('updateAvatarFile', field.files[0]);
}
});
// /client/lib/clientMethods.js
Meteor.methods({
'updateAvatarFile': function (file) {
// blabla
}
});
// /server/lib/serverMethods.js
Meteor.methods({
'updateAvatarFile': function (file) {
Avatars.insert(file, function (err, fileObj) {
if (err) {
console.log(err);
} else {
console.log(fileObj);
}
});
}
});
// /server/collections/serverAvatarCollection.js
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
//throw new Meteor.Error(403, message);
}
});
// /client/collections/clientAvatarCollection.js
// (this one is actually in a comment block)
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original"),
new FS.Store.FileSystem("thumb")
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
alert(message);
}
});
I've also tried to insert the file with the client-side method but I've got the same result (the file is added to MongoDB but not saved into a folder).
Using different path values didn't work either.
EDIT : Or maybe I'm trying to use the wrong package ? To my mind, transform a picture to chunks and save them into MongoDB sounds really weird and bad. Do you have any adivces ?
EDIT 2 :
answer to Michel Floyd (sorry about that, the character limit is annoying).
First, thanks for your answer !
1. At the moment, I'm just trying Meteor so I have both autopublish and insecure installed. Not publishing/subscribing to my collection cannot cause an issue, is that right ?
2. Before your answer I've tried to set up a collection available for both server and client by putting my avatarCollection.js in /collections. I was thinking that path which doesn't contains server or client are automatically available for the two sides. So what is the difference between /collections and /lib ? (I know that all files in a "lib" folder are loaded first). Is it a bad practice to put collections in /collections ? Maybe should I create a /lib/collections folder ?
3. (the last point, sorry for the long comment) I've tried what you advised above but it doesn't seems to work (or I am doing something wrong, again ><). When I use Avatars.insert(), CollectionFS don't save the file on my local storage. I've also checked the root of my HDD in case CollectionFS interpreted / to be the root of my machine but it doesn't. In the other hand, CollectionFS have created 4 collections in MongoDB (cfs._tempstore.chunks, cfs.avatars.filerecord, cfs_gridfs._tempstore.chunks and cfs_gridfs._tempstore.files) - the gridfs is weird. I have GridFS installed but I use FileSystem -. Those tables are not empty. That's why I think CollectionFS split my file into chunks and save them in MongoDB.
You're generally on the right track. CollectionFS uses storage adapters to deal with actual file storage. You can put files on S3, gridFS, or your local file system as you're trying to do. Putting the file contents in Mongo directly is usually avoided.
Firstly, define your collection:
Avatars = new FS.Collection("avatars", {
stores: [
new FS.Store.FileSystem("original", { path: "/public/images/user/avatar" }),
new FS.Store.FileSystem("thumb", { path: "/public/images/user/avatar" })
],
filter: {
maxSize: 1000000, //1Mo
allow: { contentTypes: ['image/*'] }
},
onInvalid: function (message) {
//throw new Meteor.Error(403, message);
}
});
in /lib! This will make it available to both the server and the client.
Secondly, make sure you publish your avatars collection from the server and subscribe to it from the client. I don't see any publish/subscribe code in your question. You need it.
Thirdly, if you just do:
Avatars.insert(...);
on the client with a file then CollectionFS then CollectionFS will take care of storing it for you. The thing is, it won't be instantly available. It can take a little while for the actual upload and storage to happen. You can look at fileObj.isUploaded for example to see if the file is ready.

How to integrate Dropzonejs with wordpress media handler in frontend?

How can I integrate Dropzonejs file uploader library in wordpress front end just like the built in one and have the uploaded one available in my media library?
Dropzonejs is a very extensive javascript library that provides a lot of options to handle media uploading.
To integrate dropzonejs with wordpress the process is pretty straight forward. Assume the following piece of code is where you want to appear your uploader.
<div id="media-uploader" class="dropzone"></div>
<input type="hidden" name="media-ids" value="">
Having a class dropzone will automatically attach the dropzone event with the element. That will stop us from overriding default parameters. So we would like to disable the auto discover feature of the library.
// Disabling autoDiscover, otherwise Dropzone will try to attach twice.
Dropzone.autoDiscover = false;
Now we will use jQuery to bind our configuration with the element.
jQuery("#media-uploader").dropzone({
url: dropParam.upload,
acceptedFiles: 'image/*',
success: function (file, response) {
file.previewElement.classList.add("dz-success");
file['attachment_id'] = response; // push the id for future reference
var ids = jQuery('#media-ids').val() + ',' + response;
jQuery('#media-ids').val(ids);
},
error: function (file, response) {
file.previewElement.classList.add("dz-error");
},
// update the following section is for removing image from library
addRemoveLinks: true,
removedfile: function(file) {
var attachment_id = file.attachment_id;
jQuery.ajax({
type: 'POST',
url: dropParam.delete,
data: {
media_id : attachment_id
}
});
var _ref;
return (_ref = file.previewElement) != null ? _ref.parentNode.removeChild(file.previewElement) : void 0;
}
});
In the code above what we have done is we attached dropzone with our element with some parameters-
url - location where we want to send our files to upload. I'll initialize the variable later.
acceptedFiles - since we are only interested in uploading images, we will limit the files to be attached only to images. You can find about more in the website of this library.
success - a callback that is fired when the file/image is uploaded successfully. It accepts two parameter the reference of the uploaded file itself and the response from the server. This is very important, here we stored the attachment id in our form. You can perform a validation here prior to store the id.
error - if the file failed to upload then you can perform any task here.
addRemoveLinks - add the remove file link below the preview panel, you can style it with your css.
removedfile - handles the operation while you click on the remove file link for an image in the preview panel. In this function we sent an ajax call to our server to remove the image from the library
Of course there are a lot of option available, but I found these are the most basic parameters I required to setup my drag-n-drop media uploader.
Now the most important thing is to decide about the file uploader url. You can have a custom file where you would want to process the operation. But I found another way.
From this question and the answer I found using admin-post.php file is pretty amazing.
Many people complained about this admin-post.php, so think sticking to the wp_ajax.php is the best option.
So I initialized the drophandler variable prior to my dropzone initialization as follows-
wp_enqueue_script('dropzone','path/to/dropzone', array('jquery'));
wp_enqueue_script('my-script','path/to/script',array('jquery','dropzone'));
$drop_param = array(
'upload'=>admin_url( 'admin-ajax.php?action=handle_dropped_media' ),
'delete'=>admin_url( 'admin-ajax.php?action=handle_deleted_media' ),
)
wp_localize_script('my-script','dropParam', $drop_param);
Now we are ready to send our images to the server. Here we will add some php code whether in the theme's function.php file or in our plugin file, but we need to be assured that it is loaded.
The following function will take care of the uploading the image and saving as an attachment in the library.
add_action( 'wp_ajax_handle_dropped_media', 'handle_dropped_media' );
// if you want to allow your visitors of your website to upload files, be cautious.
add_action( 'wp_ajax_nopriv_handle_dropped_media', 'handle_dropped_media' );
function handle_dropped_media() {
status_header(200);
$upload_dir = wp_upload_dir();
$upload_path = $upload_dir['path'] . DIRECTORY_SEPARATOR;
$num_files = count($_FILES['file']['tmp_name']);
$newupload = 0;
if ( !empty($_FILES) ) {
$files = $_FILES;
foreach($files as $file) {
$newfile = array (
'name' => $file['name'],
'type' => $file['type'],
'tmp_name' => $file['tmp_name'],
'error' => $file['error'],
'size' => $file['size']
);
$_FILES = array('upload'=>$newfile);
foreach($_FILES as $file => $array) {
$newupload = media_handle_upload( $file, 0 );
}
}
}
echo $newupload;
die();
}
The following action take care of the deletion of the media element. Second parameter of wp_delete_attachment() function allows us to decide whether we want to trash the image or completely delete it. I wanted to delete it completely so passed true.
add_action( 'wp_ajax_handle_deleted_media', 'handle_deleted_media' );
function handle_deleted_media(){
if( isset($_REQUEST['media_id']) ){
$post_id = absint( $_REQUEST['media_id'] );
$status = wp_delete_attachment($post_id, true);
if( $status )
echo json_encode(array('status' => 'OK'));
else
echo json_encode(array('status' => 'FAILED'));
}
die();
}
This will return the attachment_id in the response and we'll get it in the success function. In the media_handle_upload( $file, 0 ); I passed the reference of the file and a 0 because I didn't wanted to assign the media with any post yet (0 for no post, but if you want to assign then pass the post ID here. More reference in the codex.)
This is all for uploading media in wordpress.
Note: I haven't completed the removing uploaded file part. I'll complete this in a moment.
UPDATE
The post is updated. Now we can remove uploaded media elements from the uploader container. Thanks to this question and the answer I could figure out the actual process.
Those who are having problems getting this to work for non-admin users; please use admin-ajax.php instead of admin-post.php.
I had faced a strange issue that admin-post.php would work for non-admin users on my local server; but my live server refused to let non-admins upload files. php would echo entire page instead of the echoed value.
I replaced admin-post.php with admin-ajax.php and uploads work super cool.
I hope this helps.
The solution added to this post is incorrect unless I've misunderstood the question. Basically the solution won't work for anyone who isn't logged in as an admin. It took me 30 minutes to work it out plus the solution for removing images doesn't delete it from the media library.

Meteor/Iron-Router: how to define routes using data from settings.json

For the URL to which a route applies I have a part defined in settings.json, like this
baseUrl: '/private'
My settings are published and accessible through the collections 'Settings' (on the client). So I tried the following:
Meteor.subscribe('settings');
Deps.autorun(function () {
var settings = Settings.findOne():
if (settings) {
Router.map(function () {
this.route('project', {
path: settings.baseUrl + '/:projectId,
controller: 'ProjectController'
});
});
}
});
The problem is that during initialisation the data is not yet on the client available, so I have to wait until the data is present. So far this approach doesn't work (yet). But before spending many hours I was wondering if someone has done this before or can tell me if this is the right approach ?
Updated answer:
I published solution in repository : https://github.com/parhelium/meteor-so-inject-data-to-html
. Test it by opening url : localhost:3000/test
In this case FastRender package is useless as it injects collection data in the end of head tag -> line 63.
Inject-Initial package injects data in the beginning of head tag -> line 106.
Needed packages:
mrt add iron-router
mrt add inject-initial
Source code:
Settings = new Meteor.Collection("settings");
if (Meteor.isClient) {
var settings = Injected.obj('settings');
console.log(settings);
Router.map(function () {
this.route('postShow', {
path: '/'+settings.path,
action: function () {
console.log("dynamic route !");
}
});
});
}
if (Meteor.isServer){
if(Settings.find().count() == 0){
Settings.insert({path:"test",data:"null"});
}
Inject.obj('settings', Settings.findOne());
}
Read about security in the bottom of the page : https://github.com/gadicc/meteor-inject-initial/
OLD ANSWER :
Below solution won't work in this specific case as FastRender injects data in the end of head tag. Because of that Routes are being initialized before injected data is present.
It will work when data from Settings collection will be sent together with html.
You can do that using package FastRender.
Create file server/router.js :
FastRender.onAllRoutes(function(path) {
// don't subscribe if client is downloading resources
if(/(css|js|html|map)/.test(path)) {
return;
}
this.subscribe('settings');
});
Create also publish function:
Meteor.publish('settings', function () {
return Settings.find({});
});
The above code means that if user open any url of your app then client will subscribe to "settings" publication and data will be injected on the server into html and available for client immediately.
I use this approach to be able to connect many different domains to meteor app and accordingly sent proper data.

Cordova firefoxos web access issue

I'm trying to port my properly working (in iOS, Android) cordova app to Firefoxos.
The simulator starts properly and its browser can load web pages BUT my app cannot load data from the web.
Looking at console I see the following errors:
"JavaScript error: app://aa2a2c24-a8d6-447d-92da-4f2e9af65661/plugins/org.apache.cordova.network-information/src/firefoxos/NetworkProxy.js, line 33: missing : after property id" simulator-process.js:44
"JavaScript error: app://aa2a2c24-a8d6-447d-92da-4f2e9af65661/cordova.js, line 1120: Module org.apache.cordova.network-information.NetworkProxy does not exist."
Any suggestion? Thanks.
Cordova 3.5.0
Simulator FirfeoxOS 1.3 and FirfeoxOS 1.4
After some research I figured out the issues
1- Despite upgrading cordova to 3.5.0 I must remember that plugins don't get automatically update.
To get the plugin code for firefoxos updated I added again the same plugin, removed the firefoxos platform and reinstalled it again.
At that point the javascript errors were gone
2- Then the ajax call were still not accessible due to permissions. To ensure you can have ajax call you have to put in your manifest.webapp the following code
"type": "privileged",
"permissions": {
"systemXHR": { "description": "Required for AJAX calls in app"}
}
Both "type" and "permissions" are needed
3- Finally you have to ensure the ajax calls use
mozSystem: true
Specifically for jquery, you could put something like the following on top of your js file:
if (device.platform == 'firefoxos') {
$.ajaxPrefilter( function( options ) {
if ( options.firefoxOS ) {
options.xhr = function() {
return new window.XMLHttpRequest( {
mozSystem: true
} );
}
}
} );
$.ajaxSetup( {
firefoxOS: true
} );
}
Now I can properly handle ajax calls.

Resources