Sensenet: Check Out Documents on Upload - sensenet

When a user upload a document to a document library is possible to this documents automatically remain in the "Check Out" state?

Check the /Root/System/SystemPlugins/Portlets/IntraUploadDialog.ascx. There's a huge Javascript to handle the upload process. You can add additional functionality after upload in the fileupload's done branch.
$('#sn-upload-fileupload').fileupload({
...
done: function (e, data) {
inProgress = false;
var json = (data.jqXHR.responseText) ? jQuery.parseJSON(data.jqXHR.responseText) : data.result;
$('.sn-upload-bar', data.context).addClass('sn-upload-uploadedbar');
var filename = json.Name;
var url = json.Url;
$('.sn-upload-filetitle', data.context).html('' + filename + '');
SN.Upload.uploadFinished(data.formData.ChunkToken);
**//call an action or add custom functionality**
}
});
There are built-in odata actions in Sense/Net with which you can call actions trough ajax and there's an action for checking-out content.
http://wiki.sensenet.com/Built-in_OData_actions_and_functions#Check_out_action_-_from_version_6.3

Related

How can I cancel the uploading progress of a file in vue.js?

This is my code to upload a file, the problem that I have is that I can't cancel the uploading, what can I do in order to accomplish that?
fileBtn(e, k){
e.preventDefault();
const uploader = document.getElementById('uploader');
let size = 5242880 // equivale a 5MB -> 5242880
let getFile = e.target.files[0];
let file_type = getFile.name.split('.').pop();
let file_name = getFile.name.substr(0, getFile.name.lastIndexOf("."))
let storageRef = firebase.storage().ref('archivos/' + getFile.name);
let task = storageRef.put(getFile);
task.on('state_changed', function progress(snapshot){
// handle progress
}, function error(err){
// handle error
}, function complete(){
// handle success
);
}
I have thought to create a function in the onchange method to render a cancel button to stop de upload transaction, I thought about doing that because when a file is selected to upload, it is automatically uploaded to a database (Firebase). How can I do to avoid this and that when the file is selected, it can be accepted or canceled before the data upload transaction begins?
storageRef.put returns an UploadTask. This UploadTask has the method cancel, which does what you want. Official docs: https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#cancel
To access the upload task from another function, you need to store the task in a global variable in fileBtn:
this.task = storageRef.put(getFile); // save it globally in component
Then you need to reset the task in the event handlers (error and complete):
this.task = null
Add a button that calls e.g. cancelBtn and add this function:
cancelBtn() {
if (this.task) {
this.task.cancel()
}
}

How do you test uploading a file with Capybara and Dropzone.js?

I've switched to using the Dropzone.js plugin for drag-and-drop file uploads. How can I write a Capybara test to ensure this functionality keeps on working?
Previously I had a template with an input file element:
<input type="file" name="attachments">
And the test was simple:
When(/^I upload "([^"]*)"$/) do |filename|
attach_file("attachments", File.expand_path(filename))
# add assertion here
end
However this no longer works because Dropzone doesn't have a visible file input.
To solve this, simulate a drop event to trigger dropping an attachment onto Dropzone. First add this function to your step definition:
# Upload a file to Dropzone.js
def drop_in_dropzone(file_path)
# Generate a fake input selector
page.execute_script <<-JS
fakeFileInput = window.$('<input/>').attr(
{id: 'fakeFileInput', type:'file'}
).appendTo('body');
JS
# Attach the file to the fake input selector
attach_file("fakeFileInput", file_path)
# Add the file to a fileList array
page.execute_script("var fileList = [fakeFileInput.get(0).files[0]]")
# Trigger the fake drop event
page.execute_script <<-JS
var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } });
$('.dropzone')[0].dropzone.listeners[0].events.drop(e);
JS
end
Then test with:
When(/^I upload "([^"]*)"$/) do |filename|
drop_in_dropzone File.expand_path(filename)
# add assertion here
end
NOTE: You need to have jQuery loaded, and the Dropzone element requires the dropzone class.
These days I find this way more graceful
page.attach_file(Rails.root.join('spec/fixtures/files/avatar.png')) do
page.find('#avatar-clickable').click
end
Where is in my case #avatar-clickable is a div which contain Dropzone form tag.
Building off of #deepwell's answer which didn't quite work for me, here is a solution using vanilla JS for the events and event dispatching, and a neutral selector for the dropzone:
def drop_in_dropzone(file_path, zone_selector)
# Generate a fake input selector
page.execute_script <<-JS
fakeFileInput = window.$('<input/>').attr(
{id: 'fakeFileInput', type:'file'}
).appendTo('body');
JS
# Attach the file to the fake input selector
attach_file("fakeFileInput", file_path)
# Add the file to a fileList array
page.execute_script("fileList = [fakeFileInput.get(0).files[0]]")
# Trigger the fake drop event
page.execute_script <<-JS
dataTransfer = new DataTransfer()
dataTransfer.items.add(fakeFileInput.get(0).files[0])
testEvent = new DragEvent('drop', {bubbles:true, dataTransfer: dataTransfer })
$('#{zone_selector}')[0].dispatchEvent(testEvent)
JS
end
uses global vars on purpose, so I could test in js console, but feel free to scope them.
In case anyone is interested, I ported #deepwell's function to javascript, to use it with javascript flavoured selenium:
this.dropInDropzone = function(filePath) {
var script = "fakeFileInput = $('#fakeFileInput'); if (fakeFileInput.length === 0) fakeFileInput = window.$('<input/>').attr({id: 'fakeFileInput', type:'file'}).appendTo('body');";
// Generate a fake input selector
return driver.executeScript(script).then(function() {
// Attach the file to the fake input selector
return driver.findElement(webdriver.By.css('#fakeFileInput')).sendKeys(filePath);
}).then(function() {
// Add the file to a fileList array
return driver.executeScript("var fileList = [fakeFileInput.get(0).files[0]]");
}).then(function() {
// Trigger the fake drop event
script = "var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } }); $('.dropzone')[0].dropzone.listeners[0].events.drop(e);"
return driver.executeScript(script);
});
};
Since Capybara 3.21.0, you can drop files on elements like this:
find(".dropzone").drop(Rails.root.join("spec/fixtures/file.txt"))
See the Element#drop source for details.

What is a blob URL and why it is used?

I am having trouble with blob URLs.
I was searching for src of a video tag on YouTube and I found that the video src was like:
src="blob:https://video_url"
I opened the blob URL that was in src of the video, but it gave an error. I can't open the link, but it was working with the src tag. How is this possible?
I have a few questions:
What is a blob URL?
Why it is used?
Can I make my own blob URL on a server?
Any additional details about blob URLs would be helpful as well.
Blob URLs (ref W3C, official name) or Object-URLs (ref. MDN and method name) are used with a Blob or a File object.
src="blob:https://crap.crap" I opened the blob url that was in src of
video it gave a error and i can't open but was working with the src
tag how it is possible?
Blob URLs can only be generated internally by the browser. URL.createObjectURL() will create a special reference to the Blob or File object which later can be released using URL.revokeObjectURL(). These URLs can only be used locally in the single instance of the browser and in the same session (ie. the life of the page/document).
What is blob url?
Why it is used?
Blob URL/Object URL is a pseudo protocol to allow Blob and File objects to be used as URL source for things like images, download links for binary data and so forth.
For example, you can not hand an Image object raw byte-data as it would not know what to do with it. It requires for example images (which are binary data) to be loaded via URLs. This applies to anything that require an URL as source. Instead of uploading the binary data, then serve it back via an URL it is better to use an extra local step to be able to access the data directly without going via a server.
It is also a better alternative to Data-URI which are strings encoded as Base-64. The problem with Data-URI is that each char takes two bytes in JavaScript. On top of that a 33% is added due to the Base-64 encoding. Blobs are pure binary byte-arrays which does not have any significant overhead as Data-URI does, which makes them faster and smaller to handle.
Can i make my own blob url on a server?
No, Blob URLs/Object URLs can only be made internally in the browser. You can make Blobs and get File object via the File Reader API, although BLOB just means Binary Large OBject and is stored as byte-arrays. A client can request the data to be sent as either ArrayBuffer or as a Blob. The server should send the data as pure binary data. Databases often uses Blob to describe binary objects as well, and in essence we are talking basically about byte-arrays.
if you have then Additional detail
You need to encapsulate the binary data as a BLOB object, then use URL.createObjectURL() to generate a local URL for it:
var blob = new Blob([arrayBufferWithPNG], {type: "image/png"}),
url = URL.createObjectURL(blob),
img = new Image();
img.onload = function() {
URL.revokeObjectURL(this.src); // clean-up memory
document.body.appendChild(this); // add image to DOM
}
img.src = url; // can now "stream" the bytes
This Javascript function supports to show the difference between the Blob File API and the Data API to download a JSON file in the client browser:
/**
* Save a text as file using HTML <a> temporary element and Blob
* #author Loreto Parisi
*/
var saveAsFile = function(fileName, fileContents) {
if (typeof(Blob) != 'undefined') { // Alternative 1: using Blob
var textFileAsBlob = new Blob([fileContents], {type: 'text/plain'});
var downloadLink = document.createElement("a");
downloadLink.download = fileName;
if (window.webkitURL != null) {
downloadLink.href = window.webkitURL.createObjectURL(textFileAsBlob);
} else {
downloadLink.href = window.URL.createObjectURL(textFileAsBlob);
downloadLink.onclick = document.body.removeChild(event.target);
downloadLink.style.display = "none";
document.body.appendChild(downloadLink);
}
downloadLink.click();
} else { // Alternative 2: using Data
var pp = document.createElement('a');
pp.setAttribute('href', 'data:text/plain;charset=utf-8,' +
encodeURIComponent(fileContents));
pp.setAttribute('download', fileName);
pp.onclick = document.body.removeChild(event.target);
pp.click();
}
} // saveAsFile
/* Example */
var jsonObject = {"name": "John", "age": 30, "car": null};
saveAsFile('out.json', JSON.stringify(jsonObject, null, 2));
The function is called like saveAsFile('out.json', jsonString);. It will create a ByteStream immediately recognized by the browser that will download the generated file directly using the File API URL.createObjectURL.
In the else, it is possible to see the same result obtained via the href element plus the Data API, but this has several limitations that the Blob API has not.
I have modified working solution to handle both the case.. when video is uploaded and when image is uploaded .. hope it will help some.
HTML
<input type="file" id="fileInput">
<div> duration: <span id='sp'></span><div>
Javascript
var fileEl = document.querySelector("input");
fileEl.onchange = function(e) {
var file = e.target.files[0]; // selected file
if (!file) {
console.log("nothing here");
return;
}
console.log(file);
console.log('file.size-' + file.size);
console.log('file.type-' + file.type);
console.log('file.acutalName-' + file.name);
let start = performance.now();
var mime = file.type, // store mime for later
rd = new FileReader(); // create a FileReader
if (/video/.test(mime)) {
rd.onload = function(e) { // when file has read:
var blob = new Blob([e.target.result], {
type: mime
}), // create a blob of buffer
url = (URL || webkitURL).createObjectURL(blob), // create o-URL of blob
video = document.createElement("video"); // create video element
//console.log(blob);
video.preload = "metadata"; // preload setting
video.addEventListener("loadedmetadata", function() { // when enough data loads
console.log('video.duration-' + video.duration);
console.log('video.videoHeight-' + video.videoHeight);
console.log('video.videoWidth-' + video.videoWidth);
//document.querySelector("div")
// .innerHTML = "Duration: " + video.duration + "s" + " <br>Height: " + video.videoHeight; // show duration
(URL || webkitURL).revokeObjectURL(url); // clean up
console.log(start - performance.now());
// ... continue from here ...
});
video.src = url; // start video load
};
} else if (/image/.test(mime)) {
rd.onload = function(e) {
var blob = new Blob([e.target.result], {
type: mime
}),
url = URL.createObjectURL(blob),
img = new Image();
img.onload = function() {
console.log('iamge');
console.dir('this.height-' + this.height);
console.dir('this.width-' + this.width);
URL.revokeObjectURL(this.src); // clean-up memory
console.log(start - performance.now()); // add image to DOM
}
img.src = url;
};
}
var chunk = file.slice(0, 1024 * 1024 * 10); // .5MB
rd.readAsArrayBuffer(chunk); // read file object
};
jsFiddle Url
https://jsfiddle.net/PratapDessai/0sp3b159/
The OP asks:
What is blob URL? Why is it used?
Blob is just byte sequence. Browsers recognize Blobs as byte streams. It is used to get byte stream from source.
According to Mozilla's documentation
A Blob object represents a file-like object of immutable, raw data. Blobs represent data that isn't necessarily in a JavaScript-native format. The File interface is based on Blob, inheriting blob functionality and expanding it to support files on the user's system.
The OP asks:
Can i make my own blob url on a server?
Yes you can there are several ways to do so for example try http://php.net/manual/en/function.ibase-blob-echo.php
Read more here:
https://developer.mozilla.org/en-US/docs/Web/API/Blob
http://www.w3.org/TR/FileAPI/#dfn-Blob
https://url.spec.whatwg.org/#urls
blob urls are used for showing files that the user uploaded, but they are many other purposes, like that it could be used for secure file showing, like how it is a little difficult to get a YouTube video as a video file without downloading an extension. But, they are probably more answers. My research is mostly just me using Inspect to try to get a YouTube video and an online article.
Another use case of blob urls is to load resources from the server, apply hacks and then tell the browser to interpret them.
One such example would be to load template files or even scss files.
Here is the scss example:
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/sass.js/0.11.1/sass.sync.min.js"></script>
function loadCSS(text) {
const head = document.getElementsByTagName('head')[0]
const style = document.createElement('link')
const css = new Blob([text], {type: 'text/css'})
style.href = window.URL.createObjectURL(css)
style.type = 'text/css'
style.rel = 'stylesheet'
head.append(style)
}
fetch('/style.scss').then(res => res.text()).then(sass => {
Sass.compile(sass, ({text}) => loadCSS(text))
})
Now you could swap out Sass.compile for any kind of transformation function you like.
Blob urls keeps your DOM structure clean this way.
I'm sure by now you have your answers, so this is just one more thing you can do with it.

How to download multiple PDF files in CasperJS

I want to download a list of .pdf files from a site using CasperJS. It (mostly) works, but the last few PDF files are truncated. Here's the relevant code snippet:
casper.then(function a09() {
for (var index = bill_count-1; index>=0; --index) {
casper.then(downloadOnePdf(index));
};
});
function downloadOnePdf(index) {
return function() {
var selector = 'div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form a'
casper.log('click ' + selector, 'info');
casper.click(selector);
// casper.waitForResource(/\/Document/); -- see note
// casper.waitForText('%%EOF'); -- see note
};
};
casper.run();
Watching this code execute via web proxy, I can see the .pdf files arrive as the response body. However, the last two or three files aren't fully downloaded -- they get truncated -- and I see a message in the response header 'Client closed connection before receiving entire response'.
This supports my hunch that the casperjs code exits before the pdf is fully downloaded. I tried adding a
casper.waitForResource(/\/Document/)
in my code, but that didn't help. I also tried:
casper.waitForText('%%EOF')
but that timed out even though I could see '%%EOF' in the response body.
So the question is: what's the correct way to ensure that the entire .pdf has arrived in the response body?
ps: The observant reader will notice that I'm not actually saving the .pdf data. That's a problem for another day...
It turns out that the truncated files in the original post is only a small part of a larger problem, but the solution isn't that difficult. Let me explain...
CasperJS doesn't offer direct access to the body of a response, so the OP's approach of casper.click()ing on a form that returns the PDF data in the response won't get anywhere. AFAIK, there's no way to actually save that data on the local filesystem.
Instead, you need to call casper.download() to POST the same form that you would have gotten when you clicked on the form. The key points to this approach are straightforward, albeit thinly documented:
Load the DOM that contains the table in whatever way is appropriate
for the situation.
Use CSS's nth-child() pseudo class to select individual rows from the table.
Use casper.getFormValues() to construct a POSTable form.
Use casper.download() to post the form and save the resulting data.
The relevant code excerpts follow. I hope someone will find this useful (even if that someone is me a few months from now :)
// ========== helpers
// The following helpers assume that the current DOM contains the table with the download forms
// Return the number of PDFs available for download.
function countPDFs() {
return casper.getElementsAttribute('div#myAjaxDiv tbody tr form input[name="id"]', 'value').length
}
// Get the invoice ID of the index'th invoice: 0 <= index < countPDFs().
function getInvoiceID(index) {
return casper.getElementAttribute('div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form input[name="id"]', 'value');
}
// Return the index'th form for downloading a .pdf: 0 <= index < countPDFs().
function getDownloadForm(index) {
return casper.getFormValues('div#myAjaxDiv tbody tr:nth-child(' + (index+1) + ') form')
}
// Download the index'th PDF file, saving it to <target_directory>/<invoiceID>.pdf.
// 0 <= index < countPDFs().
function downloadOnePDF(index, target_directory) {
var
url = 'https://example.com/Invoice',
target = target_directory + '/' + getInvoiceID(index) + '.pdf',
data = getDownloadForm(index);
casper.then(function d01() {
casper.log('downloading pdf ' + index + ' to ' + url);
casper.download(url, target, 'POST', data);
});
}
// ========== casper agenda items
// (initial steps omitted)
// Click on "Invoice" button to bring up the Invoice page
var invoice_link_css = 'a#mnuInvoiceSubmit'
casper.then(function a06() {
casper.click(invoice_link_css)
});
// Make sure the Invoice page has loaded, as evidenced by the presence of the
// bill history table.
casper.then(function a07() {
casper.waitForSelector('div#myAjaxDiv tbody');
});
// Download each .pdf file referenced in the bill history table.
casper.then(function a08() {
var pdf_count = countPDFs();
casper.echo('found ' + pdf_count + ' past bill' + ((pdf_count == 1) ? '' : 's'));
for (var index = pdf_count-1; index>=0; --index) {
downloadOnePDF(index, target_directory);
}
});
casper.run();
This approach saves each .pdf file to the local filesystem, and doesn't exhibit any of the truncating problems in the OP.

How do I get data from a background page to the content script in google chrome extensions

I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.