[vscode extension API]: How to create communication channel between javascript included in `vscode.previewHtml` and outside thread? - visual-studio-code

The thing is, i am trying to create a tool with vscode.previewHtml command, I need some javascript in it listening on user's action, and send a signal to outside thread, so that i can do few high cost "native" job in background, and refresh the previewHtml with new content.
Is it possible?

I assume by "outside thread" you actually mean the hosting environment (VS code). There is no direct way (e.g. a listener/callback/method) to communicate, but you can use postMessage like so:
/* This is in a .js file you include in previewHTML. */
function exportToSVG(type) {
let html = document.querySelectorAll('html')[0];
let svg = document.querySelectorAll('svg')[0];
const args = { name: objectName, type: type, svg: svg.outerHTML, html: html.outerHTML };
window.parent.postMessage({
command: "did-click-link",
data: `command:_antlr.saveSVG?${encodeURIComponent(JSON.stringify(args))}`
}, "file://");
}
In vscode only a few commands are handled. One is that did-click-link command. You then can register to that command in your extension and do the actual work:
// This is in your extension code (usually the activate() method).
context.subscriptions.push(commands.registerCommand('_antlr.saveSVG', (args: { name: string, type: string, svg: string, html: string }) => {
window.showInputBox({
value: workspace.getConfiguration("antlr4." + args.type)["saveDir"] + "/" + args.name + ".svg",
placeHolder: "<Enter full file name here>",
prompt: "Enter the name to an svg file."
}).then((value: string) => {
...
You can use the same approach for the other direction. See for instance the markdown preview extension how to do that.

Related

Sailsjs - Cloud SDK - Blueprint API auto generated routes?

I wonder if it is possible to have the Blueprint API support in Cloud SDK.
But apparently, the generated cloud.setup.js file does not contain blueprint APIs. Just normal routes beginning with /api
It is written in the Cloud.js file :
* ### Basic Usage
*
* var user = await Cloud.findOneUser(3);
*
* var user = await Cloud.findOneUser.with({ id: 3 });
It lets think that it's possible to have auto generated routes to the blueprint APIs like actionModel -> findOneUser, createServer, addToGame, and so on...
Do you know if that is possible ? I don't find a documentation about this.
Thanks
I took original code in rebuild-cloud-sdk.js and created a rcsdk.js with the code below before the actual for (let address in sails.config.routes):
_.each(_.keys(sails.models), model => {
let action = sails.config.blueprints.prefix + sails.config.blueprints.restPrefix + '/' + model;
_.each([['GET', 'find'], ['POST', 'create']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
}
});
_.each([['GET', 'findOne'], ['PUT', 'update'], ['DELETE', 'delete']], pair => {
endpointsByMethodName[`${pair[1]}${model}`] = {
verb: pair[0],
url: action,
args: ['id'],
}
});
});
I also asked this question the other day. It is not possible. We need to be explicit here. Blueprint routes is only for quick integration testing with postman. I don't recommend this though. You should not be using postman or auto routes. You should write tests in files so they are permanent.

VueJS fileuploader

I'm searching for a vuejs file uploader component which can be integrated inside of existing form where the submission is managed by the form alone. Is there a good component in this case?
There are a couple of libraries available for file upload in VueJS. What I use is Element Components library. Here is the file upload component in Element: http://element.eleme.io/#/en-US/component/upload
You can install Element and import 'upload' component alone.
Or there are standalone components like
https://github.com/lian-yue/vue-upload-component
https://github.com/saivarunk/vue-simple-upload
https://github.com/abarta/vue2-multi-uploader
https://github.com/rowanwins/vue-dropzone
You can use this, which allows for drag and drop:
https://github.com/plantain-00/file-uploader-component
In component:
<file-uploader #file-uploaded="addFileToForm(arguments[0])" multiple="false"></file-uploader>
And in your methods:
addFileToForm(e) {
this.form.file = e // gets the full file object
this.form.file_name = e.name // get the name of the file
}
Then you can submit the form using multipart/form-data.
You can try my component which I use as filePicker:
<template>
<input v-show="showNative" type="file" :name="name" #change="onFileChanged" :multiple="multiple" :accept="accept"/>
</template>
<script>
/**
* Handles system files selection and provides the selected files.
*
* How to use:
*
* - import the component -> declare the directive.
* - provide a <name> -> is used for the formData creation (is the name which is going to backend).
* - to display it us the <show> property
* Note: sync recommended if needed to be opened multiple times in the same page. Check the bottom examples. ( /!\ Vue 2.3 required for sync /!\ )
* - listen to #files event to get an array of selected files as parameter
* - if you want to use it as multiple file select, then provide the property <multiple> as true.
* - use <accept> prop to filter the files (valid accept types: https://stackoverflow.com/questions/11832930/html-input-file-accept-attribute-file-type-csv).
* - when <showNative> is set to true, the component displays 'select file' button (input type file), otherwise it is hidden, and windows displayed by Js.
*/
export default {
props: {
name: { type: String, required: true },
show: { type: Boolean, Default: false },
multiple: { type: Boolean, default: false },
accept: { type: String, default: "" },
showNative: { type: Boolean, default: false }
},
watch: {
show(value) {
if (value) {
// Resets the file to let <onChange> event to work.
this.$el.value = "";
// Opens select file system dialog.
this.$el.click();
// Resets the show property (sync technique), in order to let the user to reopen the dialog.
this.$emit('update:show', false);
}
}
},
methods: {
onFileChanged(event) {
var files = event.target.files || event.dataTransfer.files;
if (!files.length) {
return;
}
var formData = new FormData();
// Maps the provided name to files.
formData.append(this.name, this.multiple ? files : files[0]);
// Returns formData (which can be sent to the backend) and optional, the selected files (parent component may need some information about files).
this.$emit("files", formData, files);
}
}
}
</script>
And you can use it simple like this:
SINGLE SELECT
<file-upload name="fooImport" #files="selectedFile" :show.sync="true" />
MULTIPLE SELECT
<file-upload name="barUpload" #files="selectedFiles" :show.sync="displayUpload" accept="text/plain, .pdf" />
The callback:
selectedFiles(formData) {
// FOR EXAMPLE
Axios.post('/api/upload/', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
});
},
Hope it helps :)

How to create static parameters for use in data stores with rest proxy

I have an ExtJS 5.1.2 app that utilizes throughout the app a global config set of parameters defined in app_dir/app/Application.js, that looks like:
launch: function () {
Ext.Loader.setConfig({enabled: true});
// Static parameters
cardioCatalogQT.config = {
mode: 'test', // switch to control use of staging or production server
//protocol: 'https://',
protocol: 'http://',
//host: 'production_server',
//host: 'test_server,
host: '127.0.0.1:5000',
apiGetQ: '/get_query/',
//apiGetQ: '/api/get_query/',
apiWriteQ: '/remote_query_put',
apiReadQ: '/remote_query_get',
//apiMedsMenu: '/api/meds',
//apiMedsMenu: '/meds',
remove: 'none'
};
// TODO - Launch the application
Ext.onReady(function () {
});
}
This way, I only have one place to change the parameters that make up the url in Ajax calls, (in this case protocol, host and apiGetQ, for example give mr the ability to set url = cardioCatalogQT.config.protocol + cardioCatalogQT.config.host + cardioCatalogQT.config.apiGetQ), in one place to change the server address from development -> testing -> production, instead of having to find all references throughout the app.
However, due to the way that the ExtJs loads, I cannot use these config parameters in data stores that use rest proxies, since these stores seem to load before items in the Ext.Loader.
For example, I have the following store:
Ext.define('cardioCatalogQT.store.Diagnoses', {
extend: 'Ext.data.Store',
alias: 'store.Diagnoses',
config:{
model: 'cardioCatalogQT.model.Diagnosis',
storeId: 'Diagnoses',
autoLoad: true,
proxy: {
type: 'rest',
url: 'http://127.0.0.1:5000/menu/diagnoses',
//url: 'http://test_server/menu/diagnoses',
//url: 'https://prod_server/api/menu/diagnoses',
reader: {
type: 'json',
rootProperty: 'menu_test'
}
}
}
});
So, when I change from testing to development environments, for example, I have to explicitly change the n different references for url in my n stores that have rest proxies.
Is there a way to define a config object so that I can use it for these stores? I looked at some examples of a preloader, but this did not seem to have any use cases documented for a global config object, also I had tried implementing a loadmask in a preloader, but it really screwed with the behavior of my app.
I use to do like #Alexander propose, however I'll prefer the singleton way. More ExtJs/MVC like.
So just to complete, I share my version:
/**
* #class
*/
Ext.define("MyApp.config.Config", {
alternateClassName: [
'MyApp.config'
],
singleton: true,
constant: {
// ... whatever constant you need to put here
},
constructor: function() {
var constant = this.constant;
//
// here, if you need to process some stuff
// for example calculate some constant
// which depend of other constant
//
return constant;
}
});
Require in your app
// Be sure to require your class prior
// to your app classes
Ext.define('MyApp.Application', {
extend: 'Ext.app.Application',
requires: [
'Ext.app.*',
// ext stuff ...
'MyApp.config.Config',
// myApp stuff ...
]
// ...
});
Example usage:
Ext.define('MyApp.store.MyStore', {
// ...
proxy: {
type: 'rest',
url: MyApp.config.remoteUrl
}
})
We had similar issues, so we have put our global ConnectionSettings object into a script tag that is in index.html, before Ext.
<script type="text/javascript">
ConnectionSettings = {
...
...
};
</script>
<!-- The line below must be kept intact for Sencha Cmd to build your application -->
<script id="microloader" ...
That way, the object is available wherever we need it in our Ext code.

is there possible calling gwt jsni method with chrome extension using chrome.tab.executeScript?

I have a gwt project that wrap in chrome extensions.
In GWT, I export a java method to jsni called:
Java Method: sendMessage(String msg);
export jsni: $wnd.sendMessage = function(msg) { ... };
then in chrome extension, I execute:
chrome.tabs.executeScript(tabId, {code: "sendMessage('hello');"}
but not thing happened, I've tried:
chrome.tabs.executeScript(tabId, {code: "alert('hello');"}
and it just works fine. but it just can't call my gwt jsni method.
Chrome content scripts exist in an isolated world.
$wnd.sendMessage is exported in the page context, and not accessible from a content script.
You'll need to inject code into the page itself (with a <script> tag) to access it.
See this canonical question on the topic, and this question can also be of use: Executing code at page-level from Background.js and returning the value
solved the problem, when pass a json string, you have to encode the string to prevent double quotes/special character in the string, here is my code:
assume the data format is:
var data = '{"abc":123,"cde":"kkk"}';
then encode the data:
var param = '\'' + encodeURIComponent(data) + '\'';
put then data into the code to execute:
var codeToExec = [
'var actualCode = "window.sendMessage(' + param + ');"',
'var script = document.createElement("script");',
'script.textContent = actualCode;',
'(document.head||document.documentElement).appendChild(script);',
'script.remove();'
].join('\n');
chrome.tabs.executeScript(mainTabId, {code: codeToExec});

How to reach local files with an ajax call in phonegap?

i Have this piece of code for load a json file stored in the same directory of phonegap ( iPhone ) project ( usually in the "www" folder ), how can i reach "routes.json" ?. My project have this tree folder:
__www/
___index.html
___index.json ( where is located this code )
___routes.json*
store: new Ext.data.Store({
model : 'routes',
proxy: {
type: 'ajax',
url : 'file://??????/www/routes.json',
reader: {
type: 'json'
}
},
autoLoad: true
})
Treat PhoneGap's www directory like you would a directory on your server. You can create as many sub-folders as you like, and you would reference files with relative links.
As YDL mentioned, if you're trying to access index.json and it resides at the root level of the www folder, you would use: index.json. As another example, if you had a sub-folder called data that housed all your json files, you would use: data/index.json.
I think that this is a bug in the Sencha Touch Ext.data.Proxy implementation. I spent a couple hours trying to get this work and was unsuccessful. It took me less than 5 minutes to implement it using jQuery.
//Initialize the Store
new Ext.data.Store(
{
model: "Routes",
storeId: "Routes",
//The Proxy isn't used but it is a required configuration option
proxy: {
type: 'ajax'
}
});
//Populate the store using jQuery.get()
$.get('routes.json',
function(data, status, jqXHR) {
if(status == "success") {
var store = Ext.StoreMgr.get('Routes');
store.loadData(data);
}
});