Skip to content
Permalink
Browse files

Added file opening in web! 🚀

  • Loading branch information
hamaluik committed Oct 22, 2015
1 parent 01332f6 commit 2ff2ed14df9e8fe51f0f2b5ef11ec561e5f1b1a4
Showing with 196 additions and 7 deletions.
  1. +22 −0 custom_index.html
  2. +57 −0 jslibs/FireEvent.js
  3. +6 −3 project.flow
  4. +24 −4 src/Main.hx
  5. +87 −0 src/js/FileOpener.hx
@@ -0,0 +1,22 @@
<!DOCTYPE html>
<html lang="en">

<head>

<link rel="icon" href="favicon.png"/>
<meta charset="utf-8">

<style> #window1 { margin: 0; padding: 0; } </style>

{{#each project.app.web.libs~}}
<script type="text/javascript" src="{{this}}"></script>
{{/each}}

</head>

<body style="padding: 0; margin: 0; background-color: #111111;">
<input type="file" id="filePicker" accept="image/*" hidden/>
<script type="text/javascript" src="./{{project.app.name}}{{#if project.app.web.min}}.min{{/if}}.js"></script>
</body>

</html>
@@ -0,0 +1,57 @@
/**
* Fire an event handler to the specified node. Event handlers can detect that the event was fired programatically
* by testing for a 'synthetic=true' property on the event object
* @param {HTMLNode} node The node to fire the event handler on.
* @param {String} eventName The name of the event without the "on" (e.g., "focus")
*/
function fireEvent(node, eventName) {
// Make sure we use the ownerDocument from the provided node to avoid cross-window problems
var doc;
if (node.ownerDocument) {
doc = node.ownerDocument;
} else if (node.nodeType == 9){
// the node may be the document itself, nodeType 9 = DOCUMENT_NODE
doc = node;
} else {
throw new Error("Invalid node passed to fireEvent: " + node.id);
}

if (node.dispatchEvent) {
// Gecko-style approach (now the standard) takes more work
var eventClass = "";

// Different events have different event classes.
// If this switch statement can't map an eventName to an eventClass,
// the event firing is going to fail.
switch (eventName) {
case "click": // Dispatching of 'click' appears to not work correctly in Safari. Use 'mousedown' or 'mouseup' instead.
case "mousedown":
case "mouseup":
eventClass = "MouseEvents";
break;

case "focus":
case "change":
case "blur":
case "select":
eventClass = "HTMLEvents";
break;

default:
throw "fireEvent: Couldn't find an event class for event '" + eventName + "'.";
break;
}
var event = doc.createEvent(eventClass);

var bubbles = eventName == "change" ? false : true;
event.initEvent(eventName, bubbles, true); // All events created as bubbling and cancelable.

event.synthetic = true; // allow detection of synthetic events
node.dispatchEvent(event, true);
} else if (node.fireEvent) {
// IE-old school style
var event = doc.createEventObject();
event.synthetic = true; // allow detection of synthetic events
node.fireEvent("on" + eventName, event);
}
};
@@ -13,7 +13,7 @@

project : {
name : 'AutoTerrainGen',
version : '0.1.1',
version : '0.1.2',
author : 'Darek Greenly',

app : {
@@ -22,7 +22,8 @@
web : {
libs : {
FileSaver: 'FileSaver.min.js',
pako: 'pako.min.js'
pako: 'pako.min.js',
FireEvent: 'FireEvent.js'
}
}
},
@@ -40,7 +41,9 @@
files : {
assets : 'input/',
FileSaver : 'jslibs/FileSaver.min.js => FileSaver.min.js',
pako: 'jslibs/pako.min.js => pako.min.js'
pako: 'jslibs/pako.min.js => pako.min.js',
FireEvent: 'jslibs/FireEvent.js => FireEvent.js',
index: { path:'custom_index.html => index.html', template:'project', not_listed:true }
}

}
@@ -60,6 +60,10 @@ class Main extends luxe.Game {
var export_bitmap_button:mint.Button;
var export_tsx_button:mint.Button;

#if web
var fileOpener:js.FileOpener;
#end


override public function config(config:luxe.AppConfig) {

@@ -82,6 +86,7 @@ class Main extends luxe.Game {
init_events();

#if web
fileOpener = new js.FileOpener();
load_tileset('/input/dirt16.gif');
load_tileset('/input/template16.gif');
load_tileset('/input/grass16.gif');
@@ -353,19 +358,17 @@ class Main extends luxe.Game {
closable: false,
});

#if desktop
path_input = new mint.TextEdit({
parent: window1,
#if desktop
text: 'input/',
#else
text: '/input/',
#end
text_size: 12,
name: 'path',
options: { view: { color:new Color().rgb(0x19191c) } },
x: 4, y: 35, w: 340, h: 28,
});
layout.margin(path_input, right, fixed, 58);
#end



@@ -374,11 +377,28 @@ class Main extends luxe.Game {
name: 'load',
text: 'LOAD',
options: { view: { color:new Color().rgb(0x008800) } },
#if desktop
x: 345, y: 35, w: 54, h: 28,
#elseif web
x: 4, y: 35, w: 340, h: 28,
#end
});
layout.anchor(load_button, right, right);
load_button.onmouseup.listen(function(e,_){
#if desktop
load_tileset( path_input.text );
#elseif web
fileOpener.open(function(e:Texture) {
// code taken from load_tileset
// TODO: abstract it out to keep things DRY
var ts:TileSet = new TileSet(e);
tilesets_list.add_item( create_tileset_li(ts) );

tilesets.push(ts);

generator.update_tilesets(tilesets);
});
#end
});


@@ -0,0 +1,87 @@
package js;

#if web

import phoenix.Texture;

import snow.api.buffers.Uint8Array;
import snow.system.assets.Asset.AssetImage;

import js.html.InputElement;
import js.html.File;
import js.html.FileReader;
import js.html.ProgressEvent;

import haxe.io.Bytes;
import haxe.io.BytesData;

class FileOpener {
var filePicker:InputElement;
var fileReader:FileReader;
var dataCallback:Texture->Void;

public function new() {
// find the hidden filePicker input element
// (it was placed there using the custom_index.html file)
filePicker = cast js.Browser.document.getElementById("filePicker");

// add a listener for when a user changes its value
filePicker.addEventListener('change', handleFileSelect, false);
}

public function open(dataCallback:Texture->Void) {
// simulate the user clicking on the hidden file picker
this.dataCallback = dataCallback;
untyped fireEvent(filePicker, "click");
}

private function handleFileSelect(evt) {
// make sure they actually clicked something
if(filePicker.files.length != 1) {
return;
}

var file:File = filePicker.files.item(0);
if(Luxe.resources.texture(file.name) != null) {
dataCallback(Luxe.resources.texture(file.name));
return;
}

// cancel any in-progress reads
if(fileReader != null) {
fileReader.abort();
fileReader = null;
}

// create a new file reader
fileReader = new FileReader();

// fileReader is async, so define a callback for when it's done
fileReader.onload = function(progress:ProgressEvent) {
// get the file data as bytes
var data:BytesData = cast fileReader.result;
var bytes:Bytes = Bytes.ofData(data);

// load the image using snow
Luxe.core.app.assets.image_from_bytes(file.name, Uint8Array.fromBytes(bytes))
.then(function(asset:AssetImage) {
// add the image to luxe's resources
Luxe.resources.add(new Texture({
id: file.name,
system: Luxe.resources,
width: asset.image.width,
height: asset.image.height,
pixels: asset.image.pixels
}));

// inform the caller that the image was loaded
dataCallback(Luxe.resources.texture(file.name));
});
}

// read the file data as an array buffer (which can be translated into bytes)
fileReader.readAsArrayBuffer(file);
}
}

#end

0 comments on commit 2ff2ed1

Please sign in to comment.
You can’t perform that action at this time.