I'm desperately trying to enable the multiple-property to users of my webside. User should be able to upload a bunch of PDF-files to my server without choosing each file separately. I'm using gwt-upload for my uploads. Sadly the
MultiUploader
does not actually lets the user select several files at once, but you have to click the "Browse"-Button for every file again and select in in the browser.
I researched and realised that I need to have something like this
<input name='uploads[]' type="file" multiple>
Setting the "multiple"-property at the input created from gwt-upload does the trick so far that the opening file-dialog lets me select several files, but then the upload does not start / work anymore.
I could not find any example using a multi-file-input with gwt. It would be perfect if there is a way to do this with gwt-upload because I do not really want to implement the whole upload logic by myself again!
Thanks a lot!
I use a more simple solution.
defaultUploader = new MultiUploader();
IFileInput ctrl = defaultUploader.getFileInput();
DOM.setElementProperty((ctrl).getElement(), "multiple", "multiple");
The solution is pretty simple. gwt-upload has a class Uploader which is able to do multiple uploads. The servlet code suggested in the wiki of gwt-upload is already capable of handling multiple uploads.
I had to change somethings in the Uploader class (source is fully available, so I just copied it and replaced the parts I needed). To access filenames and filesizes of the selected files I created a simple native method:
private static native String getFilesSelected() /*-{
var count = $wnd.$('input:file')[0].files.length;
var out = "";
for (i = 0; i < count; i++) {
var file = $wnd.$('input:file')[0].files[i];
out += file.name + ';' + file.size + ";";
}
return out;
}-*/;
whichs return value I split by ; to get the needed results.
And you need to replace the uploaders FileInput (setFileInput()) with a custom one, which sets the multiple property to the input. I use a wrapper class like this:
public class MyFileInput implements IFileInput {
private final FileUpload fu;
public MyFileInput() {
fu = new FileUpload();
DOM.setElementProperty(fu.getElement(), "multiple", "multiple");
}
}
you obviously need to implement the other methods of IFileInput, I linked them all through to fu. Two had no equivalent method, but I dont use them, so no problem here ...
Here's what I ended up with that I believe works on all browsers:
form = new FormPanel();
form.setEncoding(FormPanel.ENCODING_MULTIPART);
form.setMethod(FormPanel.METHOD_POST);
form.add(new HTML("<input type='file' id='fileselect' name='fileselect[]' multiple />"));
then on the server side I'm just using "org.apache.commons.fileupload" stuff.
Yeah some people may not like the HTML element in the form, but here is how you CAN get the input element from it if you want:
protected Element getFileSelectElement() {
HashMap<String, Element> idMap = Maps.newHashMap();
GuiUtil.parseIdsToMap(inputField.getElement(), idMap);
Element input = idMap.get("fileselect");
return input;
}
public static void parseIdsToMap(Element element, HashMap<String, Element> idMap) {
int nodeCount = element.getChildCount();
for (int i = 0; i < nodeCount; i++) {
Element e = (Element) element.getChild(i);
if (e.getId() != null) {
idMap.put(e.getId(), e);
}
}
}
and finally... if you want to get access to the list of files the user selected, on the browser side, here's what I have:
public static native String getFileNames(Element input) /*-{
var ret = "";
//microsoft support
if (typeof (input.files) == 'undefined'
|| typeof (input.files.length) == 'undefined') {
return input.value;
}
for ( var i = 0; i < input.files.length; i++) {
if (i > 0) {
ret += ",";
}
ret += input.files[i].name;
}
return ret;
}-*/;
Related
I am trying to create an assignment filter that filters the array so that its linked to the Course ID, however, it seems that my function is not being read so when I look to see what's inside by using the curly brackets its just shows the code, not the actual assignment.
$scope.myAssignmentFilter = function(){
for (var i = 0; i < $scope.filteredCourses.length; i++) {
if ($scope.filteredCourses[i] === $scope.assignment.CourseID){
return true;
}
}
return false;
};
I'm looking for code examples for the Gamepad API for Google Dart.
I've tried relying on the API doc directly and attempted to write out an instance for it.
//Gamepad Example:
Gamepad g = new Gamepad();
g.id.toString(); // This doesn't seem to return anything...
If anyone has any code examples for this that would be fantastic!
I tried this and it worked for me :
import "dart:html";
main(){
window.animationFrame.then(runAnimation);
}
runAnimation(timestamp){
var gamepads = window.navigator.getGamepads();
for (var pad in gamepads)
{
if(pad != null){
querySelector("#buttons").setInnerHtml("${pad.buttons.join(" ")}</br>${pad.axes.join(" ")}");
}
}
window.requestAnimationFrame(runAnimation);
}
I don't have a gamepad to try but
Gamepad g = new Gamepad();
doesn't work because Gamepade has no public constructor.
Try
var gp = window.navigator.getGamepads();
//or
// haven't tried because I don't know how to provoke this event without a gamepad
window.on['gamepadconnected'].listen((e) {
var gamepad = e.gamepad;
});
instead.
I get an empty list so I can't examine more.
see also:
- https://developer.mozilla.org/en-US/docs/Web/Guide/API/Gamepad
- https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html
Where can I read documentation concerning the execution order rules for GS files?
To dimension the problem I created two trivial objects, each in their own file.
1_File.gs
var ObjB = new Object();
ObjB.sayName = "[" + ObjA.sayName + "]";
0_File.gs
var ObjA = new Object();
ObjA.sayName = " I'm A ";
A call such as ...
Logger.log(ObjA.sayName + " : " + ObjB.sayName);
... gets the error ...
TypeError: Cannot read property "sayName" from undefined.
If I move the code from 1_File.gs into 0_File.gs, and vice versa, then there is no error and the log shows correctly ...
I'm A : [ I'm A ]
Renaming 0_File.gs to 2_File.gs doesn't affect execution order either, so I assume that order depends on which file gets created first.
Is there no concept of "include" or "import" that would allow me to make order of execution explicit?
Where can I read documentation concerning the execution order rules for GS files?
There is no such documentation and I think will not be any time published. In similar way, an initialization order of the static variables in C++ is also undefined and depends on compiler/linker.
Is there no concept of "include" or "import" that would allow me to make order of execution explicit?
Yes, there is no "includes", "imports" and even "modules", but there are libraries.
Also there is a workaround by using a closure. Bellow is a sample code. By executing the test function the log contains c.d. The idea is to have in all gs files a function started with init. In these functions all global variables are instanced. The anonymous closure is executed during the Code.gs file instancing and calls all "init" functions of all gs files.
Code.gs
var c;
function callAllInits_() {
var keys = Object.keys(this);
for (var i = 0; i < keys.length; i++) {
var funcName = keys[i];
if (funcName.indexOf("init") == 0) {
this[funcName].call(this);
}
}
}
(function() {
callAllInits_();
c = { value : 'c.' + d.value };
})();
function test() {
Logger.log(c.value);
}
d.gs
var d;
function initD() {
d = { value : 'd' };
};
I tackled this problem by creating a class in each file and making sure that each class is instantiated in the original Code.gs (which I renamed to _init.gs). Instantiating each class acts as a form of include and makes sure everything is in place before executing anything.
_init.gs:
// These instances can now be referred to in all other files
var Abc = new _Abc();
var Menu = new _Menu();
var Xyz = new _Xyz();
var Etc = new _Etc();
// We need the global context (this) in order to dynamically add functions to it
Menu.createGlobalFunctions(this);
function onInstall(e) {
onOpen(e);
}
function onOpen(e) {
Menu.build();
}
And classes usually look like this:
menu.gs:
function _Menu() {
this.build = function() {
...
}
...
}
If you have more than one level of inheritance, you need to give the init functions names like init000Foo, init010Bar, and init020Baz, and then sort the init functions by name before executing. This will ensure init000Foo gets evaluated first, then Bar, then Baz.
function callAllInits() {
var keys = Object.keys(this);
var inits = new Array();
for (var i = 0; i < keys.length; i += 1) {
var funcName = keys[i];
if (funcName.indexOf("init") == 0) {
inits.push(funcName);
}
}
inits.sort();
for (var i = 0; i < inits.length; i += 1) {
// To see init order:
// Logger.log("Initializing " + inits[i]);
this[inits[i]].call(this);
}
}
The other answers (i.e., don't write any top-level code which references objects in other files) describe the ideal way to avoid this problem. However, if you've already written a lot of code and rewriting it is not feasible, there is a workaround:
Google App Script appears to load code files in the order they were created. The oldest file first, followed by the next, and the most recently created file last. This is the order displayed in the editor when "Sort files alphabetically" is unchecked.
Thus, if you have the files in this order:
Code.gs
1_File.gs (depends on 0_File.gs)
0_File.gs
An easy fix is to make a copy of 1_File.gs and then delete the original, effectively moving it to the end of the list.
Click the triangle next to 1_File.gs and select "Make a copy"
Code.gs
1_File.gs
0_File.gs
1_File copy.gs
Click the triangle next to 1_File.gs and select "Delete"
Code.gs
0_File.gs
1_File copy.gs
Click the triangle next to 1_File copy.gs and select "Rename", then remove the " copy" from the end.
Code.gs
0_File.gs
1_File.gs
Now 0_File.gs is loaded before 1_File.gs.
This works for me as of December 2021. Quite likely, the other answers are outdated.
You can easily fix this. When you look at the scripts in the "Files" section of the web editor, you see they have an order. Files are evaluated in the order they appear there. Clicking on the three dots to the right of a file name brings up a menu that allows you to move a file up or down.
There is no such order in Google Apps Script. It purely depends on where you have these objects declared and how your function is invoked.
Can you explain a bit about how and when your Logger.log() code will be invoked.
Also, when do you declare your objects objA and objB ?
These will help us provide a better answer
here is how I would do this...
main
function include(filename) {
return ContentService.createTextOutput(filename);
}
function main() {
include('Obj A');
include('Obj B');
Logger.log(ObjA.sayName + " : " + ObjB.sayName);
}
Obj A
var ObjA = new Object();
ObjA.sayName = " I'm A ";
Obj B
var ObjB = new Object();
ObjB.sayName = "[" + ObjA.sayName + "]";
I'm using the Flex SOAP web service, connecting to our WSDL and everything is dandy. However, I'm new to web services and the web guy is on holiday, so I'm a bit confused. The first thing I'm doing is running a check connection:
private function configXMLHandler(event:LoaderEvent):void {
fws.wsdl = checkWSDL;
fws.loadWSDL();
fws.addEventListener(LoadEvent.LOAD, wsdlLoaded);
}
private function wsdlLoaded(event:LoadEvent):void {
checkAbstract = fws.getOperation("retrieveAssetIdbyLabel");
checkAbstract.arguments = ["poll-asset-do-not-remove"];
var token:AsyncToken = checkAbstract.send();
token.addResponder(new Responder(checkAbstractResult, checkAbstractError));
}
private function checkAbstractError(event:FaultEvent):void {
trace('Error in the WSDL');
}
private function checkAbstractResult(event:ResultEvent):void {
if (event.result.returnCode == 0) {
trace('Web service check ok');
initContentLoader();
} else {
trace('Error in the WSDL');
)
}
}
This works fine, I get the result I expect, and so I move on. I then need to iterate through an XML list and call the same web service function for each asset in that XML, my thinking was to use a loop:
private function initContent(event:LoaderEvent):void {
assetList = event.target.content.asset;
for (var i:int = 0; i < assetList.length(); i++) {
assetAbstract = fws.getOperation("retrieveAssetIdbyLabel");
assetAbstract.arguments = [assetList[i + assetCount].assetLabel]; //get the current index in the xmllist + the assetCount, grab the corresponding assetLabel from the XML and pass that to the web service
trace(assetAbstract.arguments);
var assetToken:AsyncToken = assetAbstract.send();
assetToken.addResponder(new Responder(getAssetResult, getAssetError));
}
}
private function getAssetResult(event:ResultEvent):void {
var treasuresAsset:TreasuresAsset = new TreasuresAsset(event.result.returnCode, assetList[assetCount].asset.assetLabel, assetList[assetCount].asset.assetImage, assetList[assetCount].asset.assetDescription);
addChild(treasuresAsset);
assetCount++; //increase the asset count
}
private function getAssetError(event:FaultEvent):void {
trace(event.fault);
trace('An error occured when we tried to get an asset id in the loop');
}
I now get an error:
Error opening URL 'http://www.nhm.ac.uk/web-services/VisitorService/'
SOAPFault (Server): org.apache.axis2.databinding.ADBException: Unexpected subelement RetrieveAssetIdbyLabel
My immediate thought was that I need to create a new instance of the web service for each asset in the xml, and repeat my first code over and over. Can I use the web service only once, do you need to recreate the entire procedure?
Thanks.
OK, so I figured this out, and it was a simple XML namespace issue.
I replaced:
assetAbstract.arguments = [assetList[i + assetCount].assetLabel];
With:
var sender:String = assetList[i + assetCount].assetLabel;
assetAbstract.arguments = [sender];
And all is working.
I'm writing a display class in Javascript (using jQuery) which may be instantiated before a web page has loaded. If the page isn't ready when the constructor is called, the instance is added to a static instances field for the class, which is iterated over when the page has loaded:
function MemDisplay(ready_callback) {
this.readyCallback = ready_callback;
if (MemDisplay.ready) {
this.linkToPage();
} else {
MemDislay.instances.push(this);
}
}
//this makes sure that the ready callback can be sent when the page has loaded
MemDisplay.ready = false;
MemDisplay.instances = [];
$(document).ready(function () {
var i;
MemDisplay.ready = true;
for (i = 0; i < MemDisplay.instances.length; i += 1) {
MemDisplay.instances[i].linkToPage();
} });
//example truncated for brevity
When I run this through JSLint, I get this error:
Problem at line 25 character 9:
'MemDislay' is not defined.
MemDislay.instances.push(this);
I need to reference MemDisplay.instances in the constructor, but the constructor is where MemDisplay is defined, so I'm puzzled about how to make this work while fitting within JSLint's guidelines. Is there a better way to do this? Should I just ignore JSLint in this instance?
JSLint here is actually highlighting a broader issue with the code without saying so.
You are referencing a class (MemDisplay) but never instantiating it as an object. I.e. you are treating the class like an already-instantiated object.
I've created a very simple equivalent to what you are trying to achieve (also at this JSFiddle)
function MyClass(p1, p2){
this.param1 = p1; //class member/property - use this to access internally.
if (this.param1 === 1){ //you might want to consider doing this as part of some setter method
alert("test");
}
this.MyMethod = function(){ //class method/function
alert("MyMethod Called");
};
}
var myObj = new MyClass(1,2); //instantiate
alert(myObj.param1); //get value of object member (you can set as well)
myObj.MyMethod(); //call a method
It'll take a bit of reorgansiation, but by declaring the values up front, you can get make JSLint happy.
My brain must have figured this out while I slept: the trick is to attach the field to the prototype, which seems pretty obvious now that I've thought of it, since that's what you have to do to define class methods.
The following checks out in JSLint, and demonstrates the sharing of a field between all instances of MyClass (or see this code on jsfiddle):
/*global alert */
function MyClass(name) {
this.name = name;
MyClass.prototype.field += 1;
}
MyClass.prototype.field = 0;
MyClass.prototype.myMethod = function () {
alert(this.name + "'s class's field is " + MyClass.prototype.field);
};
var myObj = new MyClass("first");
myObj.myMethod();
var myOtherObj = new MyClass("second");
myObj.myMethod();
myOtherObj.myMethod();
I'm not sure if there's a prettier way to do it, as having 'prototype' all over the place feels a bit excessive, on the other hand it could be a good thing because it makes it clear that prototype.field does not belong to the instance.