text: #include <AppCore/App.h>
  #include <AppCore/Window.h>
  #include <AppCore/Overlay.h>
  #include <AppCore/JSHelpers.h>
  
  using namespace ultralight;
  
  const char* htmlString();
  
  ///
  ///  Welcome to Sample 4!
  ///
  ///  In this sample we'll show how to integrate C++ code with JavaScript.
  ///
  ///  We will introduce the DOMReady event and use it to bind a C++ callback to
  ///  a JavaScript function on our page. Later, when that callback is triggered,
  ///  we will execute some JavaScript to update a hidden message on the page.
  ///
  ///  __JavaScriptCore and AppCore__
  ///
  ///  Ultralight integrates the full JavaScriptCore engine (the same JS engine
  ///  in Safari on macOS and iOS). The SDK includes full C API bindings to
  ///  JavaScriptCore which gives you a great deal of flexibility but can be a
  ///  little daunting for first-time users.
  /// 
  ///  To help simplify things, AppCore provides a simple C++ wrapper over
  ///  JavaScriptCore (@see JSHelpers.h). We'll be using this wrapper for the
  ///  sake of convenience in this sample.
  ///
  class MyApp : public WindowListener,
                public LoadListener {
    RefPtr<App> app_;
    RefPtr<Window> window_;
    RefPtr<Overlay> overlay_;
  public:
    MyApp() {
      ///
      /// Create our main App instance.
      ///
      /// The App class is responsible for the lifetime of the application
      /// and is required to create any windows.
      ///
      app_ = App::Create();
  
      ///
      /// Create our Window.
      ///
      /// This command creates a native platform window and shows it immediately.
      /// 
      window_ = Window::Create(app_->main_monitor(), 300, 300, false, kWindowFlags_Titled);
  
      ///
      /// Set our window title.
      ///
      window_->SetTitle("Ultralight Sample 4 - JavaScript");
  
      ///
      /// Register our MyApp instance as a WindowListener so we can handle the
      /// Window's OnClose event below.
      ///
      window_->set_listener(this);
  
      ///
      /// Create an Overlay using the same dimensions as our Window.
      ///
      overlay_ = Overlay::Create(*window_, window_->width(), window_->height(), 0, 0);
  
      ///
      /// Register our MyApp instance as a load listener so we can handle the
      /// View's OnDOMReady event below.
      ///
      overlay_->view()->set_load_listener(this);
  
      ///
      /// Load a string of HTML (we're using a C++11 Raw String Literal)
      ///
      overlay_->view()->LoadHTML(htmlString());
    }
  
    virtual ~MyApp() {}
  
    ///
    /// Our native JavaScript callback. This function will be called from
    /// JavaScript by calling GetMessage(). We bind the callback within
    /// the DOMReady callback defined below.
    ///
    JSValue GetMessage(const JSObject& thisObject, const JSArgs& args) {
      ///
      /// Return our message to JavaScript as a JSValue.
      ///
      return JSValue("Hello from C++!<br/>Ultralight rocks!");
    }
  
    ///
    /// Inherited from LoadListener, called when the page has finished parsing
    /// the document.
    ///
    /// We perform all our JavaScript initialization here.
    ///
    virtual void OnDOMReady(ultralight::View* caller,
                            uint64_t frame_id,
                            bool is_main_frame,
                            const String& url) override {
      ///
      /// Set our View's JSContext as the one to use in subsequent JSHelper calls
      ///
      Ref<JSContext> context = caller->LockJSContext();
      SetJSContext(context.get());
  
      ///
      /// Get the global object (this would be the "window" object in JS)
      ///
      JSObject global = JSGlobalObject();
  
      ///
      /// Bind MyApp::GetMessage to the JavaScript function named "GetMessage".
      ///
      /// You can get/set properties of JSObjects by using the [] operator with
      /// the following types as potential property values:
      ///  - JSValue
      ///      Represents a JavaScript value, eg String, Object, Function, etc.
      ///  - JSCallback 
      ///      Typedef of std::function<void(const JSObject&, const JSArgs&)>)
      ///  - JSCallbackWithRetval 
      ///      Typedef of std::function<JSValue(const JSObject&, const JSArgs&)>)
      ///
      /// We use the BindJSCallbackWithRetval macro to bind our C++ class member
      /// function to our JavaScript callback.
      ///
      global["GetMessage"] = BindJSCallbackWithRetval(&MyApp::GetMessage);
    }
  
    ///
    /// Inherited from WindowListener, called when the Window is closed.
    /// 
    /// We exit the application when the window is closed.
    ///
    virtual void OnClose(ultralight::Window* window) override {
      app_->Quit();
    }
  
    ///
    /// Inherited from WindowListener, called when the Window is resized.
    /// 
    /// (Not used in this sample)
    ///
    virtual void OnResize(ultralight::Window* window, uint32_t width, uint32_t height) override {}
  
    void Run() {
      app_->Run();
    }
  };
  
  int main() {
    MyApp app;
    app.Run();
  
    return 0;
  }
  
  const char* htmlString() {
    return R"(
  <html>
    <head>
      <style type="text/css">
        * { -webkit-user-select: none; }
        body { 
          font-family: -apple-system, 'Segoe UI', Ubuntu, Arial, sans-serif; 
          text-align: center;
          background: linear-gradient(#FFF, #DDD);
          padding: 2em;
        }
        body.rainbow {
          background: linear-gradient(90deg, #ff2363, #fff175, #68ff9d, 
                                             #45dce0, #6c6eff, #9e23ff, #ff3091);
          background-size: 1000% 1000%;
          animation: ScrollGradient 10s ease infinite;
        }
        @keyframes ScrollGradient {
          0%   { background-position:0% 50%; }
          50%  { background-position:100% 50%; }
          100% { background-position:0% 50%; }
        }
        #message {
          padding-top: 2em;
          color: white;
          font-weight: bold;
          font-size: 24px;
          text-shadow: 1px 1px rgba(0, 0, 0, 0.4);
        }
      </style>
      <script type="text/javascript">
      function HandleButton(evt) {
        // Call our C++ callback 'GetMessage'
        var message = GetMessage();
        
        // Display the result in our 'message' div element and apply the
        // rainbow effect to our document's body.
        document.getElementById('message').innerHTML = message;
        document.body.classList.add('rainbow');
      }
      </script>
    </head>
    <body>
      <button onclick="HandleButton(event);">Get the Secret Message!</button>
      <div id="message"></div>
    </body>
  </html>
      )";
  }