File access coding example

Monkey Targets Forums/HTML5/File access coding example

MonkeyPlotter(Posted 2016) [#1]
I am compiling a Monkey program that imports/parses .tcx files that are embedded within my compiled program.
I appreciate this might be a big ask, however, is anyone aware of an example of file locator logic which will allow a compiled Monkey program to:

1. Present a 'pick file' button within the GUI/web browser
2. Allow copy and pasting of a file locations text from windows explorer
3. Save the path to the file into a variable for use by the program when a 'import data' button is pressed.

[EDIT] used code from the following thread to produce a three button file selector:
http://www.monkey-x.com/Community/posts.php?topic=5698

The issue I've got at the mo is developing the syntax to detect when 3 files have been selected, then invoking the logic to run 'other' functionality (namely a data parser using the three files selected with the three buttons).

Any help invoking a 'run' button gratefully appreciated..... My attempt at using a global variable that gets incremented within each of the file classes results in only one 'browse' button being displayed. I suspect this is the wrong approach....

'original code sourced from Monkey forum posting:
'http://www.monkey-x.com/Community/posts.php?topic=5698

Strict

Import mojo

#If TARGET = "html5" Then
	Import dom.dom
	
	
	Extern
		Function log:Void(e:Event) = "window.console.log"
		Function log:Void(f:FileList) = "window.console.log"
		Function log:Void(f:File) = "window.console.log"
		
		'Global file1size:Int
		
		Class File
			Field lastModified:Int
			Field lastModifiedDate:String
			Field name:String
			Field size:Int
			Field fileName:String
			Field fileSize:Int
			Field type:String
		End Class
		
		Class FileList Extends DOMObject
			Field length:Int
			Method item:File( index:Int)
		End Class
		
		Class customHTMLInputElement Extends HTMLInputElement = "HTMLInputElement"
			Field files:FileList
		End Class
		
		'second file
		
		Class File2
			Field lastModified:Int
			Field lastModifiedDate:String
			Field name:String
			Field size:Int
			Field fileName:String
			Field fileSize:Int
			Field type:String
		End Class
		
		Class FileList2 Extends DOMObject
			Field length:Int
			Method item:File( index:Int)
		End Class
		
		Class customHTMLInputElement2 Extends HTMLInputElement = "HTMLInputElement"
			Field files:FileList2
		End Class
		
		'third file
		
		Class File3
			Field lastModified:Int
			Field lastModifiedDate:String
			Field name:String
			Field size:Int
			Field fileName:String
			Field fileSize:Int
			Field type:String
		End Class
		
		Class FileList3 Extends DOMObject
			Field length:Int
			Method item:File( index:Int)
		End Class
		
		Class customHTMLInputElement3 Extends HTMLInputElement = "HTMLInputElement"
			Field files:FileList3
		End Class
		
		'fourth file -- ideally want to change this to a button which
		' is only displayed once three files have been selected
		' which will in turn call a data parser by importing another Monkey application
		' suspect might have to embed the data parser within this file.
		
		'Class File4
		'	Field lastModified:Int
		'	Field lastModifiedDate:String
		'	Field name:String
		'	Field size:Int
		'	Field fileName:String
		'	Field fileSize:Int
		'	Field type:String
		'End Class
		
		'Class FileList4 Extends DOMObject
		'	Field length:Int
		'	Method item:File( index:Int)
		'End Class
		
		'Class customHTMLInputElement4 Extends HTMLInputElement = "HTMLInputElement"
		'	Field files:FileList4
		'End Class
		
	Public
	
		Class Listener Extends EventListener
			Method handleEvent:Int(e:Event)
				Local target:customHTMLInputElement = customHTMLInputElement(e.target)
				Select e.type
					Case "change"
						Local f:File = target.files.item(0)
						Print "new file: "+f.name+" - "+f.size+" bytes"
						
				End Select
				Return 1
			End Method
		End Class
		
		Class Listener1 Extends EventListener
			Method handleEvent:Int(e:Event)
				Local target:customHTMLInputElement2 = customHTMLInputElement2(e.target)
				Select e.type
					Case "change"
						Local f:File = target.files.item(0)
						Print "new file: "+f.name+" - "+f.size+" bytes"
						
				End Select
				Return 1
			End Method
		End Class
		
		Class Listener2 Extends EventListener
			Method handleEvent:Int(e:Event)
				Local target:customHTMLInputElement3 = customHTMLInputElement3(e.target)
				Select e.type
					Case "change"
						Local f:File = target.files.item(0)
						Print "new file: "+f.name+" - "+f.size+" bytes"
						
				End Select
				Return 1
			End Method
		End Class
		
		'Class Listener3 Extends EventListener
		'	Method handleEvent:Int(e:Event)
		'		Local target:customHTMLInputElement3 = customHTMLInputElement3(e.target)
		'		Select e.type
		'			Case "change"
		'				Local f:File = target.files.item(0)
		'				Print "new file: "+f.name+" - "+f.size+" bytes"
		'				
		'		End Select
		'		Return 1
		'	End Method
		'End Class
		
		Function Init:Void()
		
			Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
			input.type = "file"

			Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
			div.appendChild(input)
			
			Local listener:EventListener = New Listener()
			input.addEventListener("change",listener)
			
			'file1size = file1size + 1
			
		End Function
		
		Function Init2:Void()
		
			Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
			input.type = "file"

			Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
			div.appendChild(input)
			
			Local listener1:EventListener = New Listener1()
			input.addEventListener("change",listener1)
			
			'file1size = file1size + 1
			
		End Function
		
		Function Init3:Void()
		
			Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
			input.type = "file"

			Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
			div.appendChild(input)
			
			Local listener2:EventListener = New Listener2()
			input.addEventListener("change",listener2)
			
			'file1size = file1size + 1
			
		End Function
		
		'Function Init4:Void()
		
			'Local input:HTMLInputElement = HTMLInputElement(document.createElement("submit"))
			'input.type = "submit"
			
		'	Local input:HTMLInputElement = HTMLInputElement(document.createElement("input"))
		'	input.type = "file"


		'	Local div:HTMLDivElement = HTMLDivElement(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
		'	div.appendChild(input)
			
		'	Local listener3:EventListener = New Listener3()
		'	input.addEventListener("change",listener3)
			
		'End Function
#End If


Class FileApp Extends App
	Method OnCreate:Int()
		SetUpdateRate(30)
		
		Init()
		Init2()
		Init3()
		
		'failed attempt at adding logic to display a 4th 'run data parser' button once 3 files selected:
		
		'If file1size=2
		'		Init4()
		'		Endif
		
		
		Return 0
	End Method
	
	
	Method OnUpdate:Int()
	
		Return 0
	End Method
	
	
	Method OnRender:Int()
		Cls(0,0,0)
		Return 0
	End method
End Class

Function Main:Int()
	New FileApp()
	Return 0
End function



Thanks, BP.


ImmutableOctet(SKNG)(Posted 2016) [#2]
This version may be less confusing to you. It shows how to create a button and the like.

If you want something more effective for HTML5 I/O, I'd recommend my 'regal.virtualos' module. If you just want to deal with external bindings yourself, my version of the demo should get you started.

For the specific streaming features 'virtualos' has, you'll need to install the other modules. Again, that's only if you're interested in a cohesive solution. You'll still have to pipe data into it, so I only recommend my module if you're looking for a file-system.

EDIT: I just updated the demo to asynchronously load files, rather than just show how to use the API. The current version should be pretty much what you're looking for. Again, this isn't a file-system like 'regal.virtualos', but it'll allow you to load files. Obviously, this only allows you to load the file as a buffer, so you'd need to use the "Peek" commands or a 'DataStream' object to make any use of it.


ImmutableOctet(SKNG)(Posted 2016) [#3]
I forgot to mention this, but I also wrote a target or two that execute Monkey code on demand. More specifically, it lets you execute 'Main' ('bbMain'), but you get the idea. Technically you could execute any arbitrary function given the right "glue code", either from the observation end (HTML/JS), or the self-contained end (Monkey).


MonkeyPlotter(Posted 2016) [#4]
@ImmutableOctet(SKNG) Thank you for the feedback and suggestion, trying it out now.


MonkeyPlotter(Posted 2016) [#5]
@ImmutableOctet(SKNG), very excited about your help, moving forwards ;)

[EDIT]

I just need to suss how to type convert the databuffer to a dataList - I was manipulating my files individually using the following code in my data parsing Monkey code:

'## Load the Red data	
	
		file = New FileLoaderClass("testerTwo.txt")
		
		While Not file.Eof()
			dataList = dataList.Resize(dataList.Length() + 1)
			dataList[dataList.Length() - 1] = file.ReadLine()
			numberOfLines = numberOfLines + 1
		Wend



I was hoping to extract the relative path to each file, store that in a global variable, and then use the three global variables with my existing code.

However, I feel a more succinct way forward is to sort through the bytes that are stored in the data buffers by hopefully loading the dataBuffers into a dataList - I'm sure that I'll see a better way forwards after some sleep.... Need rest ;)

[EDIT] able to investigate your suggestion about the datastream object now, cheers for the help again.




MonkeyPlotter(Posted 2016) [#6]
Managing to do some byte by byte comparison in order to parse the data from files.

Probably an easier way to achieve parsing the data, which is kind of xml in format, however the syntactical sugar eludes me for now. My plan at the mo is to search for a carriage return character then use that to populate a line_string until a successive carriage return character.

	Local i:Int
		
		'okay - need to work my logic that parses files into here maybe......
		'OR how about populating the arrays I established via the following 
		'as the data transfer device
		
		If (MouseHit(MOUSE_LEFT)) Then
			For Local I:= 0 Until files.Length
				Print("File #" + (I+1) + ":")
				Print("")
				
								'parse the data from all three files into 
				If I=0
				'parse file 1 data 
				
				Print "Parsing file 1...."
				
				'For i = 0 To (dataList.Length() - 1)
				For i = 0 To (files[0].Length() - 1)
				
					Print ("i is: "+i)
					
					Print(files[I].PeekString(i))
					
					Print ("Is Byte Number: "+(files[I].PeekByte(i)))
					
					If files[I].PeekByte(i)=62
						Print "Carriage ##### return symbol maybe detected"
					Endif
					
					If files[I].PeekByte(i)=60
						Print "Lesser than <<<<< symbol detected"
					Endif
					
					
				
					'strSource = (files[i])    ' cannot convert from databuffer to string....
					'Print strSource
					
				Next
				
				Print(files[I].PeekString(i))
								
				Endif
				
				If I=1
				'parse file 2 data 



ImmutableOctet(SKNG)(Posted 2016) [#7]
You mean, like 'ReadLine'? Because as I previously brought up, 'DataStream' and 'Stream' are great ways to make your code storage agnostic. That's what they're made for. In the example I posted you could simply write:


That, or if the format is XML or XML-like, you could probably plug the data into one of the existing XML parsers. For example, Diddy has one, and SKN3 made one.

In the case of a string-based input for those parsers, you could use:


Or alternatively, you could still use a 'Stream' object and call the 'ReadString' method. In this particular case, that's probably unnecessary.

You've got options for parsing, including doing it yourself, so you shouldn't have any problems. Just as a side note, if you ever need to compare the contents of files, I wrote this module (Installed with the main repo).

Anyway, I hope those suggestions help. In general, it's best to stay within the borders of Monkey wherever possible, because that makes the code portable. Sometimes that's not realistic, but in this case, once the data is loaded, you shouldn't have any issues accessing the data from Monkey.


MonkeyPlotter(Posted 2016) [#8]
@ImmtuableOctet(SKNG)

Thanks again for the additional feedback - during the week I can only squeeze in coding when I'm dog tired - your suggestion will save me a bucket load of work that I didn't need to do.

I already have developed my own data parser using the following sytnax that works quite well, I was struggling to see how to implement manipulating the dataBuffer as a readline object.

I look forward to trying your suggestion this evening - after I've done my daily work thing ;)

This is a slice of my current data parser, where my dataList is a string object:


	Field file:FileLoaderClass
	Field dataList:String[]
	Field numberOfLines:Int
	
	file = New FileLoaderClass("testerTwo.txt")
		
		While Not file.Eof()
			dataList = dataList.Resize(dataList.Length() + 1)
			dataList[dataList.Length() - 1] = file.ReadLine()
			numberOfLines = numberOfLines + 1
		Wend

For i = 0 To (dataList.Length() - 1)
			
				count=count+1
				strSource = (dataList[i])

				If strSource[0 .. 16] = "<DistanceMeters>" Then
					distanceOneList = distanceOneList.Resize(distanceOneList.Length() + 1)
					strippedStr = strSource[16 .. 24]
					'Print "DstrippedStr = "+strippedStr
					distanceOneList[distanceOneList.Length() - 1] = strippedStr
				End If			
				
				'Print "strSource = "+strSource				
				'NOTE: Sometimes the DATE is sourced as a TIME field...need to capture that
				
				If strSource[0 .. 6] = "<Time>" Then
					timeOneList = timeOneList.Resize(timeOneList.Length() + 1)
					strippedStr = strSource[6 .. 26]
					'Print "TstrippedStr = "+strippedStr
					timeOneList[timeOneList.Length() - 1] = strippedStr
				End If
				
				If strSource[0 .. 17] = "<LatitudeDegrees>" Then
					latOneList = latOneList.Resize(latOneList.Length() + 1)
					strippedStr = strSource[17 .. 26]
					'Print "LaTstrippedStr = "+strippedStr
					latOneList[latOneList.Length() - 1] = strippedStr
				End If
				
				If strSource[0 .. 18] = "<LongitudeDegrees>" Then
					longOneList = longOneList.Resize(longOneList.Length() + 1)
					strippedStr = strSource[18 .. 28]
					'Print "LonGstrippedStr = "+strippedStr
					longOneList[longOneList.Length() - 1] = strippedStr
				End If
				
				'need logic to suss whether the BPM is over 99BPM or no (3 figs required then...
				If strSource[0 .. 7] = "<Value>" Then
					BPMOneList = BPMOneList.Resize(BPMOneList.Length() + 1)
					strippedStr = strSource[7 .. 12]
					'Print "LonGstrippedStr = "+strippedStr
					BPMOneList[BPMOneList.Length() - 1] = strippedStr
				End If
						
			Next




I'll be sure to check out your version of data parsing, as you mentioned here:


You've got options for parsing, including doing it yourself, so you shouldn't have any problems. Just as a side note, if you ever need to compare the contents of files, I wrote this module (Installed with the main repo).


My code may not necessarily be the most succinct way to achieve my goals - but its a baby steps process for moi. I genuinely appreciate your feedback - helps me retain my coding mojo ;) Right, off to work.....


MonkeyPlotter(Posted 2016) [#9]
Sorry for my ignorance, I tried invoking the following: (interpreting the INSERT_INDEX_HERE as if I entered 0 it would use the first selected file)

[EDIT] Okay, found that by simply adding Import brl.datastream (from the example within the following link) I resolved the datastream object not being identified, however, the line

 While (Not inputStream.Eof)


Cannot be used this way....? I suspect I am failing to retrieve the file data identified within the button from the LoadFile request.

https://github.com/Regal-Internet-Brothers/ioutil/blob/master/Examples/publicdatastream/TransferTo_Example.monkey

[EDIT] I found a reference to filestream here, looking around for datastream....

https://github.com/Regal-Internet-Brothers/virtualos/blob/master/filestream.monkey

Found a reference to 'publicdatastream' here:

https://github.com/Regal-Internet-Brothers/ioutil/commit/d50c85abe53c87ae77aab057817902485ed7cd95

	Method HandleEvent:Int(event:Event)
		Select event.type
			Case "change"
				Local fileButton:= GetFileButton(event.target)
				
				If (fileButton <> Null) Then
					Local f:File = fileButton.files.item(0)
					
					Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
					
					' Allocate a "shell" object.
					
					'Local buffer1:= fileButton.files.item[0]
					
					Local buffer:= files[0]
					
					'Local inputStream:= New DataStream(buffer1)
					Local inputStream:= New DataStream(buffer)

					While (Not inputStream.Eof)
						' Read the current line.
						Local line:= inputStream.ReadLine()
					Wend
					



Edit, resolved not accessing the compiler not accessing the dataStream object... as stated above.

However, I receive type 'DataStream' not found. Now I suspect I may need to include a reference to your DataStream module but am not sure how to go about achieving this.



ImmutableOctet(SKNG)(Posted 2016) [#10]

However, I receive type 'DataStream' not found. Now I suspect I may need to include a reference to your DataStream module but am not sure how to go about achieving this.



You don't have to import it unless you want a different implementation. It's separate from the official 'brl.datastream' API. You can import that module to get what you're looking for.

Just for future reference, 'brl.datastream' and 'regal.ioutil.publicdatastream' are different modules ('regal' doesn't have the standard 'brl.datastream.DataStream' class).

Likewise, the 'FileStream' implementation found in 'regal.virtualos' is different from the version in 'brl.filestream'. In that particular case, it's a reimplementation for the virtual file-system. If you want to pass data into the file-system via extensions, that's possible with '__OS_SaveBuffer', found in 'regal.virtualos.legend'.

To do something like this, you would upload to the file-system, then use 'regal.virtualos.filestream.FileStream' to load from the file-system. It's experimental, but it works well. Just keep in mind that 'regal.virtualos.filestream' is dependent on 'regal.ioutil' and co.

With that said, you don't need all of those dependencies here. If you're looking for solid behavior to manage the files, then you could use 'regal.virtualos'. However, for something this simple, it's not really needed. Useful, but not necessary. You don't seem to need to keep track of files beyond the loader, so it's not really relevant.

All you really need to do is plug the buffers into 'brl.databuffer.DataStream'. You've already got the buffers, you can just start reading from there. Streams, particularly 'brl.databuffer.DataStream' is the standard way of doing this. Just to confirm, the BRL modules are already installed. They're default modules that make up the "standard library", so you can import them anywhere you want.

The code you posted above should work just fine. As long as you're importing 'brl.datastream', then it should compile with no problems. If you've got any trouble from here, feel free to ask. Although, I recommend making multiple posts so I understand the intended message order. Edits are good for extra info that's not largely canonical.

In regards to this question:
While (Not inputStream.Eof)

Cannot be used this way....? I suspect I am failing to retrieve the file data identified within the button from the LoadFile request.


If the 'While' loop isn't working, try adding parentheses to it. It's a property in 'Stream', but some extending APIs just implement it as an undecorated method. You're probably loading the data just fine. It'd be a runtime error / exception if it failed, so if the compiler itself says there's an error, it's related to the code.


MonkeyPlotter(Posted 2016) [#11]
@ImmutableOctet(SKNG), thanks for the feedback, not normally up quite so early, thanks again for the prompt feedback, digesting your info now - hopefully I'll manage to work through your 'input' before work.

I have tried adding extra parentheses to the

While (Not inputStream.Eof)
to no avail.

Even tried modifying inputStream.Eof to DataStream.Eof to no avail:


While (Not (DataStream.Eof))
' Read the current line.
Local line:= DataStream.ReadLine()
Wend




With the inputStream.Eof commented out, the following code compiles and runs fine - I'm simply using three small text files to test the code.



here it is not 'codeboxed'

Strict

'original code sourced from Monkey forum posting:
'http://www.monkey-x.com/Community/posts.php?topic=5698

' Preprocessor related:
#MOJO_AUTO_SUSPEND_ENABLED = False

' Imports:
Import mojo
Import brl.databuffer

'attempts at getting inputstream.Eof to work
Import brl.datastream

Import brl.inputstream

' Check if we're using HTML5:
#If TARGET = "html5"
	Import dom
	
	Import "native/file_to_databuffer.js"
	
	' External bindings (JavaScript):
	Extern
	
	' Functions:
	
	' File-to-DataBuffer:
	Function LoadFile:DataBuffer(F:File, B_Out:DataBuffer)="loadFile"
	
	' DOM:
	Function log:Void(e:Event) = "window.console.log"
	Function log:Void(f:FileList) = "window.console.log"
	Function log:Void(f:File) = "window.console.log"
	'Function log:Void(o:Object) = "window.console.log"
	
	' Classes:
	Class File
		' Fields:
		Field lastModified:Int
		Field lastModifiedDate:String
		Field name:String
		Field size:Int
		Field fileName:String
		Field fileSize:Int
		Field type:String
	End
	
	Class FileList Extends DOMObject
		' Fields:
		Field length:Int
		
		' Methods:
		Method item:File(index:Int)
	End
	
	Class HTMLFileInputElement Extends HTMLInputElement = "HTMLInputElement"
		' Fields:
		Field files:FileList
	End
	
	Public
	
	' HTML5-specific Monkey code:
	
	' Globals
	
	Global file1path:String="one"
	Global file2path:String="two"
	Global file3path:String="three"
	
	
	' Classes:
	Class EventRepeater Extends EventListener
		' Constructor(s):
		Method New(Callback:EventHandler)
			Self.Callback = Callback
		End
		
		' Methods:
		Method handleEvent:Int(event:Event)
			Return Callback.HandleEvent(event)
		End
		
		' Fields:
		Field Callback:EventHandler
	End
	
	' Functions:
	Function AddFileRequester:HTMLFileInputElement(listener:EventListener, node:dom.Node)
		Local input:= HTMLFileInputElement(document.createElement("input")) ' HTMLInputElement
		
		input.type = "file"
		input.addEventListener("change", listener)
		
		node.appendChild(input)
		
		Return input
	End
	
	Function AddButton:HTMLInputElement(name:String, listener:EventListener, node:dom.Node)
		Local button:= document.createElement("input")
		
		button.setAttribute("type", "button")
		button.setAttribute("name", name)
		button.setAttribute("value", name)
		button.addEventListener("click", listener)
		
		node.appendChild(button)
		
		Return HTMLInputElement(button)
	End
#Else
	#Error "Please build this application with the HTML5 target."
#End

' Interfaces:
Interface EventHandler
	' Methods:
	Method HandleEvent:Int(event:Event)
End

' Classes:
Class FileApp Extends App Implements EventHandler
	' Constant variable(s):
	Const FILES_NEEDED:= 3
	
	' Methods:
	Method OnCreate:Int()
		SetUpdateRate(30) ' 0 ' 60
		
		Self.running = False
		Self.filesQueued = 0
		
		' This is a dummy object used to get around the limitations of DOM:
		Self.repeater = New EventRepeater(Self)
		
		Self.bodyNode = dom.Node(Element(document.getElementsByTagName("body").item(0)).getElementsByTagName("div").item(0))
		
		Self.fileButtons = New HTMLFileInputElement[FILES_NEEDED]
		Self.files = New DataBuffer[FILES_NEEDED] ' Self.fileButtons.Length
		
		For Local I:= 0 Until fileButtons.Length ' FILES_NEEDED
			Self.fileButtons[I] = AddFileRequester(repeater, bodyNode)
		Next
		
		#If CONFIG = "debug"
			MakeRunButton()
		#End
		
		Return 0
	End
	
	Method HandleEvent:Int(event:Event)
		Select event.type
			Case "change"
				Local fileButton:= GetFileButton(event.target)
				
				If (fileButton <> Null) Then
					Local f:File = fileButton.files.item(0)
					
					Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
					
					' Allocate a "shell" object: these are my attempts to get the pointer to the 
					' path to obtain the data from, I suspect I am failing to access the 
					' path to the file, or indeed the object within the Local 'f' variable
					' that refers to the file path. Suspect that could be why
					' While (Not inputStream.Eof) is failing to compile
					
					
					Local buffer:= New DataBuffer()
					
					LoadFile(f, buffer)
					files[filesQueued] = buffer
					
					'Local inputStream:= New DataStream(buffer1)
					Local inputStream:= New DataStream(buffer)
					
					'suspect I may need to 'open' the inputStream
					'here prior to accessing it ? Code compiles
					'and runs ok with the next 4 lines commented out
					
					'While (Not (inputStream.Eof))
						' Read the current line.
					'	Local line:= inputStream.ReadLine()
					'Wend

					Local buffer1:= New DataBuffer()
					Local buffer2:= New DataBuffer()
					Local buffer3:= New DataBuffer()
					
					If filesQueued = 0
					
					LoadFile(f, buffer1)
						
					files[filesQueued] = buffer1
					
					Endif
					
					If filesQueued = 1
					
					LoadFile(f, buffer2)
						
					files[filesQueued] = buffer2
					
					Endif
					
					If filesQueued = 2
					
					LoadFile(f, buffer3)
						
					files[filesQueued] = buffer3
					
					Endif		
					
					filesQueued += 1
				Endif
			Case "click"
				If (event.target = runButton) Then
					'Local runButton:= Self.runButton
					
					OnRunButtonPressed()
				Endif
		End Select
		
		Return 1
	End
	
	Method OnFilesLoaded:Void()
		If (runButton <> Null) Then
			Return
		Endif
		
		'running = True
		
		MakeRunButton()
		
		Print("All files have been loaded.")
		
		Return
	End
	
	Method OnRunButtonPressed:Void()
		If (running Or Not AllFilesLoaded) Then
			Return
		Endif
		
		running = True
		
		Print("Starting the application properly.")
		
			Print("File 1 Path is:")+file1path
			Print("File 2 Path is:")+file2path
			Print("File 3 Path is:")+file3path
			
		
		Return
	End
	
	Method MakeRunButton:Void()
		If (runButton <> Null) Then
			Return
		Endif
		
		runButton = AddButton("Run", repeater, bodyNode)
		
		Return
	End
	
	Method GetFileButton:HTMLFileInputElement(target:EventTarget)
		For Local I:= 0 Until fileButtons.Length
			If (fileButtons[I] = target) Then ' EventTarget(...)
				Return fileButtons[I]
			Endif
		Next
		
		Return Null
	End
	
	Method OnUpdate:Int()
		If (Not running) Then
			If (AllFilesLoaded) Then
				OnFilesLoaded()
			Endif
			
			Return 0
		Endif
		
		Local strSource:String
		Local i:Int
		
		'okay - need to work my logic that parses files into here maybe......
		'OR how about populating the arrays I established via the following 
		'as the data transfer device
		
		If (MouseHit(MOUSE_LEFT)) Then
			For Local I:= 0 Until files.Length
				Print("File #" + (I+1) + ":")
				Print("")
				
								'parse the data from all three files into 
				If I=0
				'parse file 1 data 
				
				Print "Parsing file 1...."
				
				'For i = 0 To (dataList.Length() - 1)
				For i = 0 To (files[I].Length() - 1)
				
					'strSource = (files[i])    ' cannot convert from databuffer to string....
					'Print strSource
					
				Next
								
				Endif
				
				If I=1
				'parse file 2 data 
				
				Print "Parsing file 2...."
				
				Endif
				
				If I=2
				'parse file 3 data 
				
				Print "Parsing file 3...."

				
				Endif
				
				
				Print(files[I].PeekString(0))
				
				
				
				If I=2
				
				Print " "
				Print "========== End of parsing files==========="
				Print " "
				
				Endif
				
				
				

				
				
				
				
				
			Next
		Endif
		
		Return 0
	End
	
	Method OnRender:Int()
		Cls()
		
		If (Not running) Then
			If (AllFilesLoaded) Then
				DrawText("All files have been loaded.", 8.0, 8.0)
			Else
				' This basically never happens.
				DrawText("Waiting for files; " + FilesCompleted + " completed.", 8.0, 8.0)
			Endif
			
			Return 0
		Endif
		
		DrawText("Running as expected, click on the screen to output all files as plain text.", 8.0, 8.0)
		
		Return 0
	End
	
	' Properties:
	Method AllFilesLoaded:Bool() Property
		Return ((filesQueued = FILES_NEEDED) And FileBuffersLoaded)
	End
	
	Method FileBuffersLoaded:Bool() Property
		For Local I:= 0 Until files.Length
			If (files[I].Length = 0) Then
				Return False
			Endif
		Next
		
		Return True
	End
	
	Method FilesCompleted:Int() Property
		Local count:= 0
		
		For Local I:= 0 Until files.Length
			Local file:= files[I]
			
			If (file <> Null And file.Length <> 0) Then
				count += 1
			Endif
		Next
		
		Return count
	End
	
	' Fields:
	Field fileButtons:HTMLFileInputElement[]
	Field runButton:HTMLInputElement
	
	Field files:DataBuffer[]
	
	Field filesQueued:Int
	Field repeater:EventRepeater
	
	Field bodyNode:dom.Node
	
	Field running:Bool
End

' Functions:
Function Main:Int()
	New FileApp()
	
	Return 0
End



MonkeyPlotter(Posted 2016) [#12]
With that said, you don't need all of those dependencies here. If you're looking for solid behavior to manage the files, then you could use 'regal.virtualos'. However, for something this simple, it's not really needed. Useful, but not necessary. You don't seem to need to keep track of files beyond the loader, so it's not really relevant.

Yes, I’m hoping to load the data into a format that my existing file parser can access without using code to glue the bytes back together to strings with carriage returns, which was the elongated path I was embarking upon prior to your help ;)


MonkeyPlotter(Posted 2016) [#13]
I think the error in my code is within the following area specifically:


				If (fileButton <> Null) Then
					Local f:File = fileButton.files.item(0)
					
					Print("New file: ~q" + f.name + "~q - " + f.size + " bytes")
					
					' Allocate a "shell" object: these are my attempts to get the pointer to the 
					' path to obtain the data from, I suspect I am failing to access the 
					' path to the file, or indeed the object within the Local 'f' variable
					' that refers to the file path. Suspect that could be why
					' While (Not inputStream.Eof) is failing to compile
					
					
					Local buffer:= New DataBuffer()
					
					LoadFile(f, buffer)
					files[filesQueued] = buffer
					
					'Local inputStream:= New DataStream(buffer1)
					Local inputStream:= New DataStream(buffer)
					
					'suspect I may need to 'open' the inputStream
					'here prior to accessing it ? Code compiles
					'and runs ok with the next 4 lines commented out
					
					While (Not (inputStream.Eof))
						' Read the current line.
						Local line:= inputStream.ReadLine()
					Wend

					Local buffer1:= New DataBuffer()
					Local buffer2:= New DataBuffer()
					Local buffer3:= New DataBuffer()




ImmutableOctet(SKNG)(Posted 2016) [#14]
Okay, I think I get what you're trying to do, but it's not quite right. I updated the example to do what you seem to be looking for. I made a change to the native JavaScript file, so you should probably download the entire thing (Click here).

I hope that helps. Everything can be done in the 'ReadLoadedFiles' method. Just for reference, I meant that you should call 'Eof()', not surround it with parentheses. To be fair, that one was my fault.


MonkeyPlotter(Posted 2016) [#15]
@SKNG, Thankyou ;) Really appreciated - I'd normally be at work by now but thanks to a docs appointment I've managed to see your resolution without tired eyes for a change. I'm still cutting my teeth with Monkey, your help is going a long way to ensuring I achieve my goal - have a good day.

I've even created my own little method:


	Method ParseLoadedFiles:Void()
	
        'TO DO: populate....
	
Return
	End



[EDIT] - Oh yes, this is exactly what I was looking for, cheers again.


MonkeyPlotter(Posted 2016) [#16]
@SKNG, Thankyou ;) Really appreciated - I'd normally be at work by now but thanks to a docs appointment I've managed to see your resolution without tired eyes for a change. I'm still cutting my teeth with Monkey, your help is going a long way to ensuring I achieve my goal - have a good day.

I've even created my own little method, the fog is slowly clearing on the Object Oriented study I did a (few) years ago now.....


Method ParseLoadedFiles:Void()
	
        'TO DO: populate....
	
         Return
End



[EDIT] - Oh yes, this is exactly what I was looking for, cheers again.