Skip to content

Commit

Permalink
Merge pull request #48691 from Faless/js/3.x_interfaces
Browse files Browse the repository at this point in the history
[HTML5] [3.x] Implement Godot <-> JavaScript interface.
  • Loading branch information
akien-mga authored May 20, 2021
2 parents 203beb6 + 730a894 commit f0fa8a1
Show file tree
Hide file tree
Showing 9 changed files with 797 additions and 172 deletions.
29 changes: 29 additions & 0 deletions doc/classes/JavaScript.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@
<link>https://docs.godotengine.org/en/3.3/getting_started/workflow/export/exporting_for_web.html#calling-javascript-from-script</link>
</tutorials>
<methods>
<method name="create_callback">
<return type="JavaScriptObject">
</return>
<argument index="0" name="object" type="Object">
</argument>
<argument index="1" name="method" type="String">
</argument>
<description>
Creates a reference to a script function that can be used as a callback by JavaScript. The reference must be kept until the callback happens, or it won't be called at all. See [JavaScriptObject] for usage.
</description>
</method>
<method name="create_object" qualifiers="vararg">
<return type="Variant">
</return>
<argument index="0" name="object" type="String">
</argument>
<description>
Creates a new JavaScript object using the [code]new[/code] constructor. The [code]object[/code] must a valid property of the JavaScript [code]window[/code]. See [JavaScriptObject] for usage.
</description>
</method>
<method name="eval">
<return type="Variant">
</return>
Expand All @@ -23,6 +43,15 @@
If [code]use_global_execution_context[/code] is [code]true[/code], the code will be evaluated in the global execution context. Otherwise, it is evaluated in the execution context of a function within the engine's runtime environment.
</description>
</method>
<method name="get_interface">
<return type="JavaScriptObject">
</return>
<argument index="0" name="interface" type="String">
</argument>
<description>
Returns an interface to a JavaScript object that can be used by scripts. The [code]interface[/code] must be a valid property of the JavaScript [code]window[/code]. The callback must accept a single [Array] argument, which will contain the JavaScript [code]arguments[/code]. See [JavaScriptObject] for usage.
</description>
</method>
</methods>
<constants>
</constants>
Expand Down
42 changes: 42 additions & 0 deletions doc/classes/JavaScriptObject.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="JavaScriptObject" inherits="Reference" version="3.4">
<brief_description>
A wrapper class for native JavaScript objects.
</brief_description>
<description>
JavaScriptObject is used to interact with JavaScript objects retrieved or created via [method JavaScript.get_interface], [method JavaScript.create_object], or [method JavaScript.create_callback].
Example:
[codeblock]
extends Node

var _my_js_callback = JavaScript.create_callback(self, "myCallback") # This reference must be kept
var console = JavaScript.get_interface("console")

func _init():
var buf = JavaScript.create_object("ArrayBuffer", 10) # new ArrayBuffer(10)
print(buf) # prints [JavaScriptObject:OBJECT_ID]
var uint8arr = JavaScript.create_object("Uint8Array", buf) # new Uint8Array(buf)
uint8arr[1] = 255
prints(uint8arr[1], uint8arr.byteLength) # prints 255 10
console.log(uint8arr) # prints in browser console "Uint8Array(10) [ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0 ]"

# Equivalent of JavaScript: Array.from(uint8arr).forEach(myCallback)
JavaScript.get_interface("Array").from(uint8arr).forEach(_my_js_callback)

func myCallback(args):
# Will be called with the parameters passed to the "forEach" callback
# [0, 0, [JavaScriptObject:1173]]
# [255, 1, [JavaScriptObject:1173]]
# ...
# [0, 9, [JavaScriptObject:1180]]
print(args)
[/codeblock]
Note: Only available in the "HTML5" platform.
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<constants>
</constants>
</class>
4 changes: 2 additions & 2 deletions platform/javascript/SCsub
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Import("env")
javascript_files = [
"audio_driver_javascript.cpp",
"http_client_javascript.cpp",
"javascript_eval.cpp",
"javascript_singleton.cpp",
"javascript_main.cpp",
"os_javascript.cpp",
"api/javascript_tools_editor_plugin.cpp",
Expand All @@ -25,7 +25,7 @@ sys_env.AddJSLibraries(
if env["tools"]:
sys_env.AddJSLibraries(["js/libs/library_godot_editor_tools.js"])
if env["javascript_eval"]:
sys_env.AddJSLibraries(["js/libs/library_godot_eval.js"])
sys_env.AddJSLibraries(["js/libs/library_godot_javascript_singleton.js"])

for lib in sys_env["JS_LIBS"]:
sys_env.Append(LINKFLAGS=["--js-library", lib])
Expand Down
34 changes: 33 additions & 1 deletion platform/javascript/api/api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@

#include "api.h"
#include "core/engine.h"
#include "javascript_eval.h"
#include "javascript_singleton.h"
#include "javascript_tools_editor_plugin.h"

static JavaScript *javascript_eval;

void register_javascript_api() {
JavaScriptToolsEditorPlugin::initialize();
ClassDB::register_virtual_class<JavaScriptObject>();
ClassDB::register_virtual_class<JavaScript>();
javascript_eval = memnew(JavaScript);
Engine::get_singleton()->add_singleton(Engine::Singleton("JavaScript", javascript_eval));
Expand All @@ -61,10 +62,41 @@ JavaScript::~JavaScript() {}

void JavaScript::_bind_methods() {
ClassDB::bind_method(D_METHOD("eval", "code", "use_global_execution_context"), &JavaScript::eval, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_interface", "interface"), &JavaScript::get_interface);
ClassDB::bind_method(D_METHOD("create_callback", "object", "method"), &JavaScript::create_callback);
{
MethodInfo mi;
mi.name = "create_object";
mi.arguments.push_back(PropertyInfo(Variant::STRING, "object"));
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "create_object", &JavaScript::_create_object_bind, mi);
}
}

#if !defined(JAVASCRIPT_ENABLED) || !defined(JAVASCRIPT_EVAL_ENABLED)
Variant JavaScript::eval(const String &p_code, bool p_use_global_exec_context) {
return Variant();
}

Ref<JavaScriptObject> JavaScript::get_interface(const String &p_interface) {
return Ref<JavaScriptObject>();
}

Ref<JavaScriptObject> JavaScript::create_callback(Object *p_ref, const StringName &p_method) {
return Ref<JavaScriptObject>();
}

Variant JavaScript::_create_object_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
if (p_argcount < 1) {
r_error.error = Variant::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
r_error.argument = 0;
return Ref<JavaScriptObject>();
}
if (p_args[0]->get_type() != Variant::STRING) {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::STRING;
return Ref<JavaScriptObject>();
}
return Ref<JavaScriptObject>();
}
#endif
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*************************************************************************/
/* javascript_eval.h */
/* javascript_singleton.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
Expand Down Expand Up @@ -28,10 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/

#ifndef JAVASCRIPT_EVAL_H
#define JAVASCRIPT_EVAL_H
#ifndef JAVASCRIPT_SINGLETON_H
#define JAVASCRIPT_SINGLETON_H

#include "core/object.h"
#include "core/reference.h"

class JavaScriptObject : public Reference {
private:
GDCLASS(JavaScriptObject, Reference);

protected:
virtual bool _set(const StringName &p_name, const Variant &p_value) { return false; }
virtual bool _get(const StringName &p_name, Variant &r_ret) const { return false; }
virtual void _get_property_list(List<PropertyInfo> *p_list) const {}
};

class JavaScript : public Object {
private:
Expand All @@ -44,10 +55,13 @@ class JavaScript : public Object {

public:
Variant eval(const String &p_code, bool p_use_global_exec_context = false);
Ref<JavaScriptObject> get_interface(const String &p_interface);
Ref<JavaScriptObject> create_callback(Object *p_ref, const StringName &p_method);
Variant _create_object_bind(const Variant **p_args, int p_argcount, Variant::CallError &r_error);

static JavaScript *get_singleton();
JavaScript();
~JavaScript();
};

#endif // JAVASCRIPT_EVAL_H
#endif // JAVASCRIPT_SINGLETON_H
79 changes: 0 additions & 79 deletions platform/javascript/javascript_eval.cpp

This file was deleted.

Loading

0 comments on commit f0fa8a1

Please sign in to comment.