Simpler WYSIWYG HTML Editor. Wie?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Re: Simpler WYSIWYG HTML Editor. Wie?

Beitrag von ts-soft »

Kukulkan hat geschrieben:und auch ohne RTF Konvertierungen meinerseits.
Das wäre aber IMHO die simpelste Lösung, die zudem Dein Programm nicht aufbläht.

Da würde ich an Deiner Stelle nochmals drüber Nachdenken :wink:

Gruß
Thomas
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Simpler WYSIWYG HTML Editor. Wie?

Beitrag von Kiffi »

hier mal ein WYSIWYG-Beispiel auf WebGadget-Basis.

Als WYSIWYG-Komponente kommt hier das dojotoolkit zum Einsatz

Code: Alles auswählen

Enumeration
  #frmWYSIWYG
EndEnumeration
Enumeration
  #frmWYSIWYG_cmdTest
  #frmWYSIWYG_Browser
EndEnumeration

Enumeration   ; VARENUM
  #VT_EMPTY = 0
  #VT_NULL = 1
  #VT_I2 = 2
  #VT_I4 = 3
  #VT_R4 = 4
  #VT_R8 = 5
  #VT_CY = 6
  #VT_DATE = 7
  #VT_BSTR = 8
  #VT_DISPATCH = 9
  #VT_ERROR = 10
  #VT_BOOL = 11
  #VT_VARIANT = 12
  #VT_UNKNOWN = 13
  #VT_DECIMAL = 14
  #VT_I1 = 16
  #VT_UI1 = 17
  #VT_UI2 = 18
  #VT_UI4 = 19
  #VT_I8 = 20
  #VT_UI8 = 21
  #VT_INT = 22
  #VT_UINT = 23
  #VT_VOID = 24
  #VT_HRESULT = 25
  #VT_PTR = 26
  #VT_SAFEARRAY = 27
  #VT_CARRAY = 28
  #VT_USERDEFINED = 29
  #VT_LPSTR = 30
  #VT_LPWSTR = 31
  #VT_RECORD = 36
  #VT_INT_PTR = 37
  #VT_UINT_PTR = 38
  #VT_FILETIME = 64
  #VT_BLOB = 65
  #VT_STREAM = 66
  #VT_STORAGE = 67
  #VT_STREAMED_OBJECT = 68
  #VT_STORED_OBJECT = 69
  #VT_BLOB_OBJECT = 70
  #VT_CF = 71
  #VT_CLSID = 72
  #VT_VERSIONED_STREAM = 73
  #VT_BSTR_BLOB = $fff
  #VT_VECTOR = $1000
  #VT_ARRAY = $2000
  #VT_BYREF = $4000
  #VT_RESERVED = $8000
  #VT_ILLEGAL = $ffff
  #VT_ILLEGALMASKED = $fff
  #VT_TYPEMASK = $fff
EndEnumeration

#DISPATCH_METHOD = $1
#DISPATCH_PROPERTYGET = $2
#DISPATCH_PROPERTYPUT = $4
#DISPATCH_PROPERTYPUTREF = $8

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

Procedure MakeBSTR(String$)
  Unicode$ = Space(Len(String$)*2+2)
  MultiByteToWideChar_(#CP_ACP, 0, @String$, -1, @Unicode$, Len(String$)*2+2)
  ProcedureReturn SysAllocString_(@Unicode$)
EndProcedure

Procedure.s ReadBSTR(bstr)
  length = WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, 0, 0, 0, 0)
  Text$ = Space(length)
  WideCharToMultiByte_(#CP_ACP, 0, bstr, -1, @Text$, length, 0, 0)   
  ProcedureReturn Text$
EndProcedure

Procedure.s StringFromVARIANT(*var.VARIANT)

  If VariantChangeType_(*var, *var, $2, #VT_BSTR) = #S_OK
    Result$ = ReadBSTR(*var\bstrVal)
    SysFreeString_(*var\bstrVal)
  Else
    Result$ = "ERROR : Cannot convert VARIANT to String!"
  EndIf
  
  ProcedureReturn Result$
EndProcedure

Procedure.s ExecuteJavaScript(Gadget, Function$, Arguments$, Separator$)
  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_command = MakeBSTR(Function$)
        result = Script\GetIDsOfNames(?IID_NULL, @bstr_command, 1, 0, @dispID.l)
        If result = #S_OK
          
          ; parse the arguments          
          ;
          If Trim(Arguments$) = ""
            Count = 0
            *Arguments = 0
          Else            
            Count = CountString(Arguments$, Separator$)+1
            *Arguments = AllocateMemory(SizeOf(VARIANT)*Count)       
            *Arg.VARIANT = *Arguments
            
            For i = 1 To Count            
              *Arg\vt = #VT_BSTR
              *Arg\bstrVal = MakeBSTR(StringField(Arguments$, i, Separator$))
              *Arg + SizeOf(VARIANT)
            Next i
          EndIf
          
          params.DISPPARAMS\cArgs = Count
          params\cNamedArgs = 0
          params\rgvarg = *Arguments
          
          result = Script\Invoke(dispID, ?IID_NULL, 0, #DISPATCH_METHOD, @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
          
          If *Arguments
            *Arg.VARIANT = *Arguments
            For i = 1 To Count
              SysFreeString_(*Arg\bstrVal)
              *Arg + SizeOf(VARIANT)
            Next i          
            FreeMemory(*Arguments)
          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_command)
                      
        Script\Release()
      EndIf
      Document\Release()
    EndIf
    DocumentDispatch\Release()
  EndIf

  ProcedureReturn Result$
EndProcedure

; Hier geht's lo-hos...

Define.s HTML

OpenWindow(#frmWYSIWYG, #PB_Ignore, #PB_Ignore, 600, 400, "WYSIWYG-Demo")
ButtonGadget(#frmWYSIWYG_cmdTest, 10, 5, 120, 25, "Get editor content...")
WebGadget(#frmWYSIWYG_Browser, 0, 30, 600, 360, "")

HTML + "<!DOCTYPE HTML PUBLIC ''-//W3C//DTD HTML 4.01//EN'' ''http://www.w3.org/TR/html4/strict.dtd''>"
HTML + "<html dir=''ltr''>"
HTML + "    <head>"
HTML + "        <style type=''text/css''>"
HTML + "            body, html { font-family:helvetica,arial,sans-serif; font-size:90%; }"
HTML + "        </style>"
HTML + "        <script src=''http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js'' djConfig=''parseOnLoad: true''>"
HTML + "        </script>"
HTML + "        <script type=''text/javascript''>"
HTML + "            dojo.require(''dijit.Editor'');"

HTML + "  function GetEditorContent() { return dijit.byId(''editor1'').attr(''value'') };"

HTML + "        </script>"
HTML + "        <link rel=''stylesheet'' type=''text/css'' href=''http://ajax.googleapis.com/ajax/libs/dojo/1.6/dijit/themes/claro/claro.css'' />"
HTML + "    </head>"
HTML + "    <body class='' claro ''>"
HTML + "        <div dojoType=''dijit.Editor'' id=''editor1''>"
HTML + "            <p>"
HTML + "                This instance is created from a div directly with default toolbar and"
HTML + "                plugins"
HTML + "            </p>"
HTML + "        </div>"
HTML + "    </body>"
HTML + "</html>"

HTML = ReplaceString(HTML, "''", Chr(34))

SetGadgetItemText(#frmWYSIWYG_Browser, #PB_Web_HtmlCode, HTML)

Repeat
  WWE=WaitWindowEvent()
  Select WWE
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #frmWYSIWYG_cmdTest
          MessageRequester("", ExecuteJavaScript(#frmWYSIWYG_Browser, "GetEditorContent", "", ""))
      EndSelect
    Case #PB_Event_CloseWindow
      Break 
  EndSelect
ForEver
ExecuteJavaScript() und der Klimbim drumherum habe ich von freak geklaut:
http://www.purebasic.fr/english/viewtop ... 94#p104594

Das Beispiel ist aufgrund der API-Aufrufe Win-only. Eine
Crossplattformlösung gibt es IMO nicht.

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
Kiffi
Beiträge: 10711
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: Simpler WYSIWYG HTML Editor. Wie?

Beitrag von Kiffi »

Kiffi hat geschrieben:Eine Crossplattformlösung gibt es IMO nicht.
ups! Posting von DarkDragon übersehen...

// Edit: Jetzt auch crossplattformfähig (Danke an DD für den Trick):

Code: Alles auswählen

Enumeration
  #frmWYSIWYG
EndEnumeration
Enumeration
  #frmWYSIWYG_cmdTest
  #frmWYSIWYG_Browser
EndEnumeration

Define.s HTML

OpenWindow(#frmWYSIWYG, #PB_Ignore, #PB_Ignore, 600, 400, "WYSIWYG-Demo")
ButtonGadget(#frmWYSIWYG_cmdTest, 10, 5, 120, 25, "Get editor content...")
WebGadget(#frmWYSIWYG_Browser, 0, 30, 600, 360, "")

HTML + "<!DOCTYPE HTML PUBLIC ''-//W3C//DTD HTML 4.01//EN'' ''http://www.w3.org/TR/html4/strict.dtd''>"
HTML + "<html dir=''ltr''>"
HTML + "    <head>"
HTML + "        <style type=''text/css''>"
HTML + "            body, html { font-family:helvetica,arial,sans-serif; font-size:90%; }"
HTML + "        </style>"
HTML + "        <script src=''http://ajax.googleapis.com/ajax/libs/dojo/1.6/dojo/dojo.xd.js'' djConfig=''parseOnLoad: true''>"
HTML + "        </script>"
HTML + "        <script type=''text/javascript''>"
HTML + "            dojo.require(''dijit.Editor'');"

HTML + "  function SetDocumentTitle() { document.title=dijit.byId(''editor1'').attr(''value'') };"

HTML + "        </script>"
HTML + "        <link rel=''stylesheet'' type=''text/css'' href=''http://ajax.googleapis.com/ajax/libs/dojo/1.6/dijit/themes/claro/claro.css'' />"
HTML + "    </head>"
HTML + "    <body class='' claro ''>"
HTML + "        <div dojoType=''dijit.Editor'' id=''editor1'' onDisplayChanged=''SetDocumentTitle();''>"
HTML + "            <p>"
HTML + "                This instance is created from a div directly with default toolbar and"
HTML + "                plugins"
HTML + "            </p>"
HTML + "        </div>"
HTML + "    </body>"
HTML + "</html>"

HTML = ReplaceString(HTML, "''", Chr(34))

SetGadgetItemText(#frmWYSIWYG_Browser, #PB_Web_HtmlCode, HTML)

Repeat
  WWE=WaitWindowEvent()
  Select WWE
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #frmWYSIWYG_cmdTest
          MessageRequester("", GetGadgetItemText(#frmWYSIWYG_Browser, #PB_Web_PageTitle))
      EndSelect
    Case #PB_Event_CloseWindow
      Break 
  EndSelect
ForEver
Weitere Infos zum Editor: http://docs.dojocampus.org/dijit/Editor

Grüße ... Kiffi
a²+b²=mc²
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Simpler WYSIWYG HTML Editor. Wie?

Beitrag von Danilo »

Kukulkan hat geschrieben:@Danilo
Ja, im Prinzip will ich nur rudimentäres. Allerdings ohne HTML Kenntnisse der Nutzer und auch ohne RTF Konvertierungen meinerseits. Kann Scintilla denn als WYSIWYG Editor funktionieren? Ich dachte, Scintilla macht nur Syntax-Highlighting (nehme ich heute für den HTML Editor-Part)?
Ich kenne mich mit Scintilla nicht aus, kann also nicht sagen ob es als
wirklicher WYSIWYG-Editor arbeiten kann.
Aber sowas wie Wordpad sollte man damit sicherlich machen können,
wenn man sich bissl einliest.

Nach kurzer Boardsuche (http://forums.purebasic.com/german/view ... 16&t=24132)
konnte ich dieses Beispiel erstellen:

Code: Alles auswählen

#font     = "Arial"
#fontsize = 14

Enumeration
  #DEFAULT   = 0
  #BOLD      = 1
  #ITALIC    = 4
  #UNDERLINE = 8
EndEnumeration

Procedure SetStyle(style,font$,fontsize,fontcolor,flag)
    ScintillaSendMessage(0,#SCI_STYLESETFONT, style, @font$)
    ScintillaSendMessage(0,#SCI_STYLESETSIZE, style, fontsize)
    ScintillaSendMessage(0,#SCI_STYLESETFORE ,style, fontcolor)
    If flag&#BOLD
        ScintillaSendMessage(0,#SCI_STYLESETBOLD     ,style, 1)
    EndIf
    If flag&#ITALIC
        ScintillaSendMessage(0,#SCI_STYLESETITALIC   ,style, 1)
    EndIf
    If flag&#UNDERLINE
        ScintillaSendMessage(0,#SCI_STYLESETUNDERLINE,style, 1)
    EndIf
EndProcedure

Procedure InitStyles()
    SetStyle(#DEFAULT                   ,#font,#fontsize  ,RGB($00,$00,$00),#DEFAULT)
    SetStyle(#BOLD                      ,#font,#fontsize  ,RGB($FF,$00,$00),#BOLD)
    SetStyle(#ITALIC                    ,#font,#fontsize-6,RGB($80,$80,$80),#ITALIC)
    SetStyle(#UNDERLINE                 ,#font,#fontsize  ,RGB($00,$00,$FF),#UNDERLINE)
    SetStyle(#BOLD|#UNDERLINE           ,#font,#fontsize  ,RGB($00,$00,$00),#BOLD|#UNDERLINE)
    SetStyle(#BOLD|#ITALIC              ,#font,#fontsize  ,RGB($00,$00,$00),#BOLD|#ITALIC)
    SetStyle(#BOLD|#ITALIC|#UNDERLINE   ,#font,#fontsize-4,RGB($00,$00,$00),#BOLD|#ITALIC|#UNDERLINE)
EndProcedure

Procedure StyleChars(start,length,style)
    ScintillaSendMessage(0,#SCI_STARTSTYLING,start,255)
    ScintillaSendMessage(0,#SCI_SETSTYLING,length,style)
EndProcedure

Procedure AddLine(text$)
    text$+Chr(10)
    len = Len(text$)
    text2$=Space(len*4)
    PokeS(@text2$,text$,len,#PB_UTF8) ; convert to UTF8
    ScintillaSendMessage(0, #SCI_APPENDTEXT, MemoryStringLength(@text2$,#PB_UTF8), @text2$)
EndProcedure


If OpenWindow(0, 0, 0, 500, 300, "ScintillaGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    If InitScintilla()
        ScintillaGadget(0, 0, 0, 500, 300, #Null)

        ScintillaSendMessage(0,#SCI_SETMARGINWIDTHN,1,0)        ; margin
        ScintillaSendMessage(0,#SCI_SETCODEPAGE,#SC_CP_UTF8,0)  ; UTF8 mode

        InitStyles()
        
        AddLine("Hallo Kukulkan!")
        AddLine("Das ist ein Scintilla-Gadget")
        AddLine("mit Styles")
        AddLine("")
        AddLine("Ä Ö Ü ä ö ü ß")

        StyleChars(0 ,15,#BOLD)
        StyleChars(16,28,#ITALIC)
        StyleChars(45,3 ,#UNDERLINE)
        StyleChars(49,6 ,#BOLD|#UNDERLINE|#ITALIC)
        
    EndIf
    Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf 
Bold, Italic, Underline, versch. Fonts und Fontgrößen gehen also
auf jeden Fall mit Scintilla.

EDIT: UTF8 bei Scintilla eingeschalten, geht nun auch mit Unicode.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Kukulkan
Beiträge: 1066
Registriert: 09.09.2004 07:07
Wohnort: Süddeutschland
Kontaktdaten:

Re: Simpler WYSIWYG HTML Editor. Wie?

Beitrag von Kukulkan »

Hallo Danilo, Kiffi und andere,

vielen Dank für die super Hilfe. Ich werde mir das mal in Ruhe ansehen und dann für den nächsten Release eine der Varianten einbauen.

DANKE!!!! :allright:

Kukulkan
Antworten