Page 1 of 1

WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 9:44 am
by firace
Experimental, for simple HTML content.
Use as a starting point - adapt to your needs!

Code: Select all


code$ + "<link href=https://cdn.quilljs.com/1.3.6/quill.snow.css rel=stylesheet>" + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "<div style=height:400px id=editor>" + #CRLF$ 
code$ + "  <p>Hello World!</p>" + #CRLF$ 
code$ + "  <p>Some initial <strong>bold</strong> text</p><p><em style=color:red;>Open</em>Window(0, 100, 100)</p>" + #CRLF$ 
code$ + "  <p><br></p>" + #CRLF$ 
code$ + "</div>" + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "<script src=https://cdn.quilljs.com/1.3.6/quill.js></script>" + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "<script>" + #CRLF$ 
code$ + "var toolbarOptions = [" + #CRLF$ 
code$ + "  ['bold', 'italic', 'underline', 'strike'],        // toggled buttons" + #CRLF$ 
code$ + "  ['blockquote', 'code-block']," + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "  [{ 'header': 1 }, { 'header': 2 }],               // custom button values" + #CRLF$ 
code$ + "  [{ 'list': 'ordered'}, { 'list': 'bullet' }]," + #CRLF$ 
code$ + "  [{ 'indent': '-1'}, { 'indent': '+1' }],          // outdent/indent" + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "  [{ 'size': ['small', false, 'large', 'huge'] }],  // custom dropdown" + #CRLF$ 
code$ + "  ['link', 'image']," + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "  [{ 'color': [] }, { 'background': [] }],          // dropdown with defaults from theme" + #CRLF$ 
code$ + "  [{ 'font': [] }]," + #CRLF$ 
code$ + "  [{ 'align': [] }]," + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "  ['clean']                                         // remove formatting button" + #CRLF$ 
code$ + "];" + #CRLF$ 
code$ + "" + #CRLF$ 
code$ + "var quill = new Quill('#editor', {" + #CRLF$ 
code$ + "  modules: {" + #CRLF$ 
code$ + "    toolbar: toolbarOptions" + #CRLF$ 
code$ + "  }," + #CRLF$ 
code$ + "  theme: 'snow'" + #CRLF$ 
code$ + "});" + #CRLF$ 
code$ + "  " + #CRLF$ 
code$ + "</script>"

Define.s regkeyName, dwLabel, statusMsg, keyResult.i


regkeyName    = "Software\Microsoft\Internet Explorer\Main\FeatureControl\Feature_Browser_Emulation\"
dwLabel = GetFilePart(ProgramFilename())

dwValue = 11001   
RegOpenKeyEx_(#HKEY_CURRENT_USER, regkeyName,  0, #KEY_ALL_ACCESS, @keyResult) 
RegSetValueEx_(keyResult, @dwLabel, 0, #REG_DWORD, @dwValue, SizeOf(Long))


DataSection 
  IID_IHTMLDocument2: ; {332C4425-26CB-11D0-B483-00C04FD90119} 
  Data.l $332C4425 
  Data.w $26CB, $11D0 
  Data.b $B4, $83, $00, $C0, $4F, $D9, $01, $19 
EndDataSection 


Procedure.i WebGadget_GetHTMLDocument2 (nGadget)
  Protected oBrowser.IWebBrowser2 = GetWindowLongPtr_(GadgetID(nGadget), #GWL_USERDATA)
  Protected oDocumentDispatch.IDispatch
  Protected oHTMLDocument.IHTMLDocument2
  Protected iBusy
  
  Repeat
    While WindowEvent(): Delay(0): Wend    
    oBrowser\get_Busy(@iBusy): Delay(10)        
  Until iBusy = #VARIANT_FALSE
  
  If oBrowser
    If oBrowser\get_document(@oDocumentDispatch) = #S_OK 
      If oDocumentDispatch\QueryInterface(?IID_IHTMLDocument2, @oHTMLDocument) = #S_OK
        oDocumentDispatch\Release()
      EndIf
    EndIf
  EndIf
  
  ProcedureReturn oHTMLDocument 
EndProcedure

Procedure.i WebGadget_GetHTMLDocumentParent (nGadget)
  Protected oHTMLDocument.IHTMLDocument2 = WebGadget_GetHTMLDocument2 (nGadget)
  Protected oWindow.IHTMLWindow2
  
  If oHTMLDocument
    oHTMLDocument\get_parentWindow(@oWindow)
  EndIf
  
  oHTMLDocument\Release()  
  
  ProcedureReturn oWindow
EndProcedure 

Procedure WebGadget_ExecScript (nGadget, sScriptCode.s, sScriptLanguage.s = "JavaScript")    
  Protected oWindow.IHTMLWindow2 = WebGadget_GetHTMLDocumentParent (nGadget)
  Protected tVariant.VARIANT
  
  If oWindow
    oWindow\execScript (sScriptCode, sScriptLanguage, @tVariant)
    oWindow\Release()
  EndIf    
EndProcedure 

DataSection
  IID_IHTMLDocument: ; {626FC520-A41E-11CF-A731-00A0C9082637}
  Data.l $626FC520
  Data.w $A41E, $11CF
  Data.b $A7, $31, $00, $A0, $C9, $08, $26, $37
  
  IID_NULL: ; {00000000-0000-0000-0000-000000000000}
  Data.l $00000000
  Data.w $0000, $0000
  Data.b $00, $00, $00, $00, $00, $00, $00, $00       
EndDataSection



; >>> MakeBSTR <<<

CompilerIf #PB_Compiler_Processor = #PB_Processor_x86
  Import ""
    MakeBSTR(str.p-unicode) As "_SysAllocString"
  EndImport
CompilerElse
  Import ""
    MakeBSTR(str.p-unicode) As "SysAllocString"
  EndImport
CompilerEndIf

; >>> StringFromVARIANT <<<

Procedure.s StringFromVARIANT(*var.VARIANT)
  
  If VariantChangeType_(*var, *var, $2, #VT_BSTR) = #S_OK
    Result$ = PeekS(*var\bstrVal, -1, #PB_Unicode)
    SysFreeString_(*var\bstrVal)
  Else
    Result$ = "ERROR : Cannot convert VARIANT to String!"
  EndIf
  
  ProcedureReturn Result$
EndProcedure


Procedure.s GetJSVariable(Gadget, Name$)
  Result$ = "ERROR" 
  
  Browser.IWebBrowser2 = GetWindowLong_(GadgetID(Gadget), #GWL_USERDATA)
  If Browser\get_Document(@DocumentDispatch.IDispatch) = #S_OK
    If DocumentDispatch\QueryInterface(?IID_IHTMLDocument, @Document.IHTMLDocument) = #S_OK
      If Document\get_Script(@Script.IDispatch) = #S_OK
        
        bstr_name = MakeBSTR(Name$)
        result = Script\GetIDsOfNames(?IID_NULL, @bstr_name, 1, 0, @dispID.l)
        If result = #S_OK
          
          params.DISPPARAMS\cArgs = 0
          params\cNamedArgs = 0        
          
          result = Script\Invoke(dispID, ?IID_NULL, 0, #DISPATCH_PROPERTYGET, @params, @varResult.VARIANT, 0, 0)
          If result = #S_OK
            Result$ = StringFromVARIANT(@varResult)
          Else
            Message$ = Space(3000)
            FormatMessage_(#FORMAT_MESSAGE_IGNORE_INSERTS|#FORMAT_MESSAGE_FROM_SYSTEM, 0, result, 0, @Message$, 3000, 0)          
            Result$ = "ERROR: Invoke() "+Message$            
          EndIf
          
        Else
          Message$ = Space(3000)
          FormatMessage_(#FORMAT_MESSAGE_IGNORE_INSERTS|#FORMAT_MESSAGE_FROM_SYSTEM, 0, result, 0, @Message$, 3000, 0)          
          Result$ = "ERROR: GetIDsOfNames() "+Message$          
          
        EndIf
        SysFreeString_(bstr_name)
        
        Script\Release()
      EndIf
      Document\Release()
    EndIf
    DocumentDispatch\Release()
  EndIf
  
  ProcedureReturn Result$
EndProcedure


Enumeration
  #Gadget_Web
  #Gadget_Text
  #Gadget_Button
  #Gadget_Button2
EndEnumeration






OpenWindow(0, 0, 0, 1000, 600, "WYSIWYG", #PB_Window_ScreenCentered|#PB_Window_MinimizeGadget)

WebGadget(#Gadget_Web, 5, 5, 990, 530, "")    

SetGadgetItemText(#Gadget_Web, #PB_Web_HtmlCode, code$)

ButtonGadget(#Gadget_Button2, 440, 550, 210, 30, "Save as HTML")

Repeat
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Gadget And EventGadget() = #Gadget_Button2
    script.s = "var c=document.getElementsByClassName('ql-editor')[0].innerHTML;" 
    WebGadget_ExecScript (#Gadget_Web, script.s) 
    res$ = GetJSVariable(#Gadget_Web,"c")
    res$ = "<head><meta http-equiv='X-UA-Compatible' content='IE=edge' /><link href=https://cdn.quilljs.com/1.3.6/quill.snow.css rel=stylesheet></head><span class='ql-editor'>" + res$
    
    filename$ = SaveFileRequester("Save HTML", GetUserDirectory(#PB_Directory_Desktop), "HTML (*.html)", 0)
    if not FindString(filename$, ".") : filename$ + ".html": endif 
    OpenFile(1, filename$) : WriteString(1, res$) : CloseFile(1)
  EndIf
  
Until Event = #PB_Event_CloseWindow

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 10:27 am
by BarryG
Wow, this is impressive! Thanks for sharing.

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 2:16 pm
by Oso
It looks very good indeed. Do you plan to be able to open existing HTML content, firace?

Just bearing in mind that the default HTML code in fact contains the icon section, so that has to be preserved, regardless of what's being edited as new content.

What about the editing, are you relying on Quill to do that?

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 2:24 pm
by jacdelad
This is really cool. And so tiny!

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 3:06 pm
by ChrisR
Nicely done, a simple and effective little WYSIWYG HTML editor and so tiny indeed, thank you for sharing :)

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 3:16 pm
by Rinzwind
Read as Quill js text editor

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 7:08 pm
by firace
Yes this is built with Quill which does the editing work (didn't feel like reinventing the wheel)
and PB captures the resulting HTML through the webgadget and some API tricks

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Oct 25, 2023 9:16 pm
by firace
Fixed some bugs - updated code in the top post.

Re: WYSIWYG HTML editor (Windows)

Posted: Wed Nov 08, 2023 11:36 pm
by firace
[removed obsolete post]

Re: WYSIWYG HTML editor (Windows)

Posted: Sun Nov 12, 2023 2:40 pm
by firace
I just created a little appplication based on this approach - see here:

viewtopic.php?t=82852

Re: WYSIWYG HTML editor (Windows)

Posted: Fri Nov 17, 2023 3:42 am
by ricardo
Hi,

Very nice !!

One question, can you add that we can trigger some purebasic from some event (click a button oper example)?

Re: WYSIWYG HTML editor (Windows)

Posted: Fri Nov 17, 2023 5:06 pm
by firace
ricardo wrote: Fri Nov 17, 2023 3:42 am Hi,

Very nice !!

One question, can you add that we can trigger some purebasic from some event (click a button oper example)?
Thanks ricardo. Can you clarify what you mean?
It's possible to trigger PB code from HTML using the CreateExternalDispatch / ScriptRaiseEventCallback method, but I think you already know this :)

Re: WYSIWYG HTML editor (Windows)

Posted: Sat Nov 18, 2023 3:34 pm
by ricardo
firace wrote: Fri Nov 17, 2023 5:06 pm
ricardo wrote: Fri Nov 17, 2023 3:42 am Hi,

Very nice !!

One question, can you add that we can trigger some purebasic from some event (click a button oper example)?
Thanks ricardo. Can you clarify what you mean?
It's possible to trigger PB code from HTML using the CreateExternalDispatch / ScriptRaiseEventCallback method, but I think you already know this :)
Yes, i know how to do it.

I was tired when i write this, please forget about it and don't tell anybody :)

Thank you for your nice code !!

Re: WYSIWYG HTML editor (Windows)

Posted: Sun Dec 03, 2023 9:32 pm
by Kwai chang caine
Really nice code, that I hadn't seen :oops:
Thanks for sharing 8)

Re: WYSIWYG HTML editor (Windows)

Posted: Sun Dec 03, 2023 10:37 pm
by firace
Kwai chang caine wrote: Sun Dec 03, 2023 9:32 pm Really nice code, that I hadn't seen :oops:
Thanks for sharing 8)
Thanks!

You can also look at this version, which is (slightly) more advanced:
https://www.purebasic.fr/english/viewtopic.php?t=82852