Editable WebGadget library

Share your advanced PureBasic knowledge/code with the community.
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Editable WebGadget library

Post by zapman* »

Thanks to Fr34k, I understood how the Interface of Internet Explorer works and how to use it through a WebGadget. I began to make a WYSIWYG Html Editor and created many procedure to rich this target.

You can download the open source resulting library at
http://www.rankspirit.com/downloads/wg_library.zip

This file includes about 60 procedures (with comments) to deal with the Internet Explorer Interface.
Don't try - DO it !
User avatar
Flype
Addict
Addict
Posts: 1542
Joined: Tue Jul 22, 2003 5:02 pm
Location: In a long distant galaxy

Post by Flype »

seems good zapman.
can you provide a small example, please ?
No programming language is perfect. There is not even a single best language.
There are only languages well suited or perhaps poorly suited for particular purposes. Herbert Mayer
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Looks promising! Thanks.

Second the request for a small example.
Dare2 cut down to size
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

Here it is:

Code: Select all

XIncludeFile "WebGadgetExtras.pb"
;
ButtonWidth = 60 : ButtonHeight = 18 : ButtonLineHeight = ButtonHeight + 6
;
MyWindow=OpenWindow(#PB_Any,0,0,600,400,"WebgadgetLibrary demo",#PB_Window_ScreenCentered|#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget | #PB_Window_SizeGadget | #PB_Window_TitleBar) 
If CreateGadgetList(WindowID(MyWindow))=0:End:EndIf
;
WebGadget = WebGadget(#PB_Any,0,0,WindowWidth(MyWindow),WindowHeight(MyWindow)-ButtonLineHeight,"about:blank")
;
HTMLSample$ = "<html><head></head><body><div align="+Chr(34)+"center"+Chr(34)+"><p>WebGadget Library demo</p><p>&nbsp;</p><p>By Fr34k And Zapman</p></div></body></html>"
SetDocumentHTMLContent(WebGadget,HTMLSample$)
;
HPos = 5
ButtonFind = ButtonGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight-2,ButtonWidth,ButtonHeight,"Find")
HPos + ButtonWidth +10
ComboContent = ComboBoxGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight-4,100,100)
AddGadgetItem(ComboContent,-1,"Element 0 infos")
AddGadgetItem(ComboContent,-1,"Element 1 infos")
AddGadgetItem(ComboContent,-1,"Element 2 infos")
AddGadgetItem(ComboContent,-1,"Element 3 infos")
AddGadgetItem(ComboContent,-1,"Element 4 infos")
AddGadgetItem(ComboContent,-1,"Element 5 infos")
AddGadgetItem(ComboContent,-1,"Element 6 infos")
AddGadgetItem(ComboContent,-1,"Element 7 infos")
SetGadgetState(ComboContent,0)
HPos  +102
ButtonDisplay = ButtonGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight-2,ButtonWidth,ButtonHeight,">>Display")
HPos  + ButtonWidth + 10
ButtonEdit = ButtonGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight-2,80,ButtonHeight,"Edit mode")
HPos  + 80 + 10
ButtonRankSpirit = ButtonGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight-2,ButtonWidth,ButtonHeight,"RankSpirit")
HPos  + ButtonWidth + 40
MouseText = TextGadget(#PB_Any,HPos,WindowHeight(MyWindow)-ButtonHeight,130,ButtonHeight,"Last clic was over...")

EditMode$ = "Off"
Repeat  
  ;
  EventID = WaitWindowEvent()
  If  EventID = #PB_Event_CloseWindow
    Quit = 1
  ElseIf EventID=#WM_SIZE
    ResizeGadget(WebGadget,#PB_Ignore,#PB_Ignore,WindowWidth(MyWindow),WindowHeight(MyWindow)-ButtonLineHeight)
    ResizeGadget(ButtonFind,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight-2,#PB_Ignore,#PB_Ignore)
    ResizeGadget(ComboContent,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight-4,#PB_Ignore,#PB_Ignore)
    ResizeGadget(ButtonDisplay,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight-2,#PB_Ignore,#PB_Ignore)
    ResizeGadget(ButtonEdit,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight-2,#PB_Ignore,#PB_Ignore)
    ResizeGadget(ButtonRankSpirit,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight-2,#PB_Ignore,#PB_Ignore)
    ResizeGadget(MouseText,#PB_Ignore,WindowHeight(MyWindow)-ButtonHeight,#PB_Ignore,#PB_Ignore)
  ElseIf EventID = #WM_LBUTTONDOWN
    GetWindowRect_(GadgetID(WebGadget),re.RECT) 
    GetCursorPos_(pt.POINT)
    ;
    If pt\y<re\bottom
      pt\x - re\left
      pt\y - re\top
      x = pt\X
      y = pt\y
      GetElementInfosFromPoint(WebGadget,x,y,@Element.ElementInfo)
      SetGadgetText(MouseText,"Last clic was over: "+Element.ElementInfo\tagname)
      SetGadgetState(ComboContent,Element\Index)
    EndIf
    
  ElseIf EventID=#PB_Event_Gadget
    If EventGadget() = ButtonFind
      SearchString$ = InputRequester("Search","Enter the expression to search:","Zapman")
      If SearchString$
        FindInWebGadget(SearchString$,0,WebGadget)
      EndIf
    ElseIf EventGadget() = ButtonDisplay
      Index = GetGadgetState(ComboContent)
      If Index<0 : Index = 0 : EndIf
      GetElementInfosFromIndex(WebGadget,Index,Element.ElementInfo)
      tx$ = "TagPosition: "+Element\taglist+Chr(13)
      tx$ + "posX: "+Str(Element\offsetTop)+Chr(13)
      tx$ + "posY: "+Str(Element\offsetLeft)+Chr(13)+Chr(13)
      tx$ + "Content: "+ Element\outerHTML
      MessageRequester("Element 1 content",tx$,0)
    ElseIf EventGadget() = ButtonEdit
      If EditMode$ = "Off"
        EditMode$ = "On"
        SetGadgetText(ButtonEdit,"Browser Mode")
      Else
        EditMode$ = "Off"
        SetGadgetText(ButtonEdit,"Edit Mode")
      EndIf
      SetWebGadgetEditable(WebGadget,EditMode$)
    ElseIf EventGadget() = ButtonRankSpirit
      SetGadgetText(WebGadget,"about:<body><h1>Loading...</h1></body>")
      While WindowEvent() : Wend
      SetGadgetText(WebGadget,"http://www.rankspirit.com")
      SetWebGadgetEditable(WebGadget,EditMode$)
        
    EndIf
  EndIf
Until Quit
Don't try - DO it !
Tranquil
Addict
Addict
Posts: 952
Joined: Mon Apr 28, 2003 2:22 pm
Location: Europe

Post by Tranquil »

Great!! many thanks for shareing!
Tranquil
Denis
Enthusiast
Enthusiast
Posts: 778
Joined: Fri Apr 25, 2003 5:10 pm
Location: Doubs - France

Post by Denis »

Excellent !
A+
Denis
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi zapman*,

Thanks again. This is really useful.

Edit:

This is weird. If I replace the HTMLSample$="html stuff" with

Code: Select all

HTMLSample$=""
ReadFile(2,"path\to\test.html")
While Not Eof(2)
  HTMLSample$ + ReadString(2)
Wend
CloseFile(2)
Then it runs only once in every (about) 5 times. The other times it just disappears. MessageRequesters show it doesn't even get as far as the structures in the "extras" file. (They don't pop up)

However if I don't do the read, or place something like:

Code: Select all

HTMLSample$="<html><title>A</title><head></head><body>OK</body></html>"
immediately after the read (thus negating the efforts of the read) then it always works!

Any ideas? (the test file is about 2k in size.)

Edit again:

Using

Code: Select all

FileBuffersSize(2,0)
makes it work nearly every time.

Is there a way to know if a file operation is really completed?


Edit yet again:

Okay, this is not the place for this question, I'll take it to coding questions as I don't think it has anything to do with this (except incidentally).
Dare2 cut down to size
Bonne_den_kule
Addict
Addict
Posts: 841
Joined: Mon Jun 07, 2004 7:10 pm

Post by Bonne_den_kule »

Use FlushFileBuffers()
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi Bonne_den_kule,

Thanks for the suggestion.

Actually zapman* pointed me at the problem in a post in coding questions (I had threadsafe on to test a possible bug for someone and forgot to turn it off).

zapman*, this lib is really great, thanks - and for the good call. :)
Dare2 cut down to size
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi zapman*,

Just remembered this thread was around so decided to be a pain and post a question for you here.

Do you know how to insert HTML at a given point in the document using this approach? That is, insert actual HTML at the caret position so that it shows as html and not htmldecoded text?

(Please say yes - oh - and please show how!)

Thanks!
Dare2 cut down to size
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

Hi Dare

Using the example described in this topic, add a button and exec the following when you clic on this button:

Code: Select all

StringToPaste$ = "<h1>Just to try</h1>"
      #OLECMDID_PASTE = 13
      VarIn.variant\VT = #VT_BSTR
      VarIn\bstrVal = StringToBStr (StringToPaste$)
      WebGadget_Exec(WebGadget,#OLECMDID_PASTE,#OLECMDEXECOPT_DONTPROMPTUSER,@VarIn,@VarOut.variant)
      SysFreeString_(VarIn\bstrVal)
by that way, the "<h1>Just to try</h1>" code is not interpreted but just past "as it" into the page.

Is it what you were looking at?
Don't try - DO it !
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi zapman*,

Thanks for the response!

Mate, sorry for the confusing request.

I can paste/insert text, what I am looking to do is insert html so the the html is encoded and behaves like HTML. So inserting something like "<b>BOLD</b>" would produce BOLD.

I know things like Bold, Italic, Fonts, colours and etc can be set, images can be inserted, etc, etc, using #IDM_constants and am doing that. However there are cases where I need to be able to insert chunks of html code and have them wysiwyg-ed.

I cannot work out how to get the html in there and make it act like HTML! I am in danger of going bald trying to do this. :)

Perhaps I need to get the caret or selection position, get the inner html (<body>) into a string, parse the string to locate caret/selection position, and then insert the desired code, cut the original selection (if selection), clear the doc, rewrite the updated string, reposition caret/selection. Fiddly.

There must be a cleaner way. I just cannot find it. :?

If you have the answer, great! But if you have to spend time chasing it, please don't, I don't want to waste your time. Just hoping you have the answer at your fingertips.


Thanks for your help so far.


PS: I believe there is a command PasteHTML available via MSHTML.DLL which I assume would do the job, however I don't know how to access/use it.
Dare2 cut down to size
zapman*
Enthusiast
Enthusiast
Posts: 115
Joined: Wed Jun 02, 2004 10:17 pm
Location: New Caledonia (South Pacific)
Contact:

Post by zapman* »

Dear Dare,

I'm working on exactly the same problem as you since four weeks and i'm completely bald actually.

I tried a dozain of different solutions to get the user-selected (highlighted) html code, transform it by my own procedures and replace it inside the document. And now, I hate hate hate hate the Microsoft developpers who worked on IE Explorer. IE is probably the worst part of Windows in terms of liability and logic. Many functions are buggy and written with the 4th dimension's way of thincking. I'm not used to be critical about Microsoft but I'm badly training myself at this occasion.

Just as an example, when you try to get the html code matching with a selection using ANY of the IE functions, the code returned is not the "real" one. ie:
Suppose that the user has selected the words "some words" in a sentence as "some words of a sample text" included in a h1 tag. You expect to get something as

Code: Select all

 <h1>some words
but you will get

Code: Select all

 <h1>some words</h1>
(IE will "complete" the code before giving it to you).
So, when you want to transform this code and to reinsert it into your document, you will obtain something like

Code: Select all

 <h1>some words</h1> of a sample text</h1>
After all that pain, I personally concluded that there is not any "elegant" way of doing that and that the only reliable one is to do approx what you suggest:
get the caret or selection position, get the inner html (<body>) into a string, parse the string to locate caret/selection position, and then insert the desired code, cut the original selection (if selection), clear the doc, rewrite the updated string, reposition caret/selection
I'm actually making a last attempt to paste the transformed code inside the document instead of
clear the doc, rewrite the updated string, reposition caret/selection
but I have not finished.

Here are two of my procedures (not well tested) to do that:
(those procedures use my version of the WebGadgetExtra library which you can download using the link at the beggining of this topic)

Code: Select all

Procedure.s PutMyMarkupsAndGetTheElementCode(WebGadget) ; by Zapman
 TextRange.IHTMLTxtRange = GetTxtRange(WebGadget)
  If TextRange
    bstr.l = 0
    If TextRange\get_text(@bstr) = #S_OK And bstr And PeekS(bstr,-1,#PB_Unicode)
      SelectedText$ = PeekS(bstr,-1,#PB_Unicode)
      SysFreeString_(bstr)
      If TextRange\parentElement(@Element.IHTMLElement) = #S_OK And Element
        bstr.l = 0
        If Element\get_outerText(@bstr) = #S_OK And bstr And PeekS(bstr,-1,#PB_Unicode)
          ElementText$ = PeekS(bstr,-1,#PB_Unicode)
          SysFreeString_(bstr)
          MarkupServices.IMarkupServices = GetIMarkupServices(WebGadget)
          If MarkupServices
            MarkupServices\CreateMarkupPointer (@MarkupPointer1.IMarkupPointer)
            If MarkupPointer1
              MarkupServices\CreateMarkupPointer (@MarkupPointer2.IMarkupPointer)
              If MarkupPointer2
                If Trim(SelectedText$) = Trim(ElementText$) ; Selection matchs with the whole Element content -> Include the tags into the selection.
                  MarkupPointer1\MoveAdjacentToElement(Element,#ELEM_ADJ_BeforeBegin)
                  MarkupPointer2\MoveAdjacentToElement(Element,#ELEM_ADJ_AfterEnd)
                Else
                  MarkupServices\MovePointersToRange(TextRange,MarkupPointer1,MarkupPointer2)
                EndIf
                InsertedString1$ = "hereisthestartoftheoldcode"
                bStr = StringToBStr (InsertedString1$)
                MarkupServices\InsertText(bStr,Len(InsertedString1$),MarkupPointer1)
                SysFreeString_(bStr)
                InsertedString2$ = "hereistheendoftheoldcode"
                bStr = StringToBStr (InsertedString2$)
                MarkupServices\InsertText(bStr,Len(InsertedString2$),MarkupPointer2)
                SysFreeString_(bStr)
                MarkupPointer2\Release()
                If Element\get_outerHTML(@bStr) = #S_OK And bStr
                  Result$ = ReadBSTR(bstr)
                  SysFreeString_(bStr)
                  If FindString(Result$,InsertedString1$,0)=0 Or FindString(Result$,InsertedString2$,0)=0 ; one of the markups has been inserted before the entry tag of after the ending tag
                    If Element\get_parentElement(@Parent.IHTMLElement) = #S_OK And Parent
                      Element\Release()
                      Element = Parent
                      If Element\get_outerHTML(@bStr) = #S_OK And bStr
                        Result$ = ReadBSTR(bstr)
                        SysFreeString_(bStr)
                      EndIf
                    Else
                      Result$ = ""
                    EndIf
                  EndIf
                EndIf
              EndIf
              MarkupPointer1\Release()
            EndIf
            MarkupServices\Release()
          EndIf
        EndIf
        Element\Release()
      EndIf
    EndIf
    TextRange\Release() 
  EndIf
  ProcedureReturn Result$
EndProcedure
;
Procedure RemoveMyMarkupsAndSelectTextInside(WebGadget) ; by Zapman
  TextRange.IHTMLTxtRange = GetTxtRange(WebGadget)
  If TextRange
    MarkupServices.IMarkupServices = GetIMarkupServices(WebGadget)
    If MarkupServices
      If TextRange\parentElement(@Element.IHTMLElement) = #S_OK And Element 
        MarkupServices\CreateMarkupPointer (@MarkupPointerS1.IMarkupPointer)
        If MarkupPointerS1
          MarkupServices\CreateMarkupPointer (@MarkupPointerS2.IMarkupPointer)
          If MarkupPointerS2
            MarkupPointerS1\MoveAdjacentToElement(Element,#ELEM_ADJ_BeforeBegin) ; Extend TextRange to the whole Element content
            MarkupPointerS2\MoveAdjacentToElement(Element,#ELEM_ADJ_AfterEnd)
            MarkupServices\MoveRangeToPointers(MarkupPointerS1,MarkupPointerS2,TextRange)
            bStr = StringToBStr ("hereisthestartoftheoldcode")
            varOut.VARIANT\vt = #VT_BOOL
            If TextRange\findText(PeekS(bstr, -1, #PB_Unicode),$7FFFFFFF,0,@varOut) = #S_OK       ; look for the first markup
              MarkupServices\MovePointersToRange(TextRange,MarkupPointerS1,MarkupPointerS2)
              MarkupServices\Remove(MarkupPointerS1,MarkupPointerS2)                                                   ; remove my first markup
              bStr = StringToBStr ("hereistheendoftheoldcode")
              varOut.VARIANT\vt = #VT_BOOL
              If TextRange\findText(PeekS(bstr, -1, #PB_Unicode),$7FFFFFFF,0,@varOut) = #S_OK      ; look for the second markup
                MarkupServices\CreateMarkupPointer (@MarkupPointerE1.IMarkupPointer)
                If MarkupPointerE1
                  MarkupServices\CreateMarkupPointer (@MarkupPointerE2.IMarkupPointer)
                  If MarkupPointerE2
                    MarkupServices\MovePointersToRange(TextRange,MarkupPointerE1,MarkupPointerE2)
                    MarkupServices\Remove(MarkupPointerE1,MarkupPointerE2)                                              ; remove my second markup
                    MarkupServices\MoveRangeToPointers(MarkupPointerS1,MarkupPointerE2,TextRange)
                     TextRange\select()
                    MarkupPointerE2\Release()
                    Result = 1
                  EndIf ; If MarkupPointerE2
                  MarkupPointerE1\Release()
                EndIf ; If MarkupPointerE1
              EndIf ; If TextRange\findText(PeekS(bstr, -1, #PB_Unicode),$7FFFFFFF,0,@varOut) = #S_OK
            EndIf ; If TextRange\findText(PeekS(bstr, -1, #PB_Unicode),$7FFFFFFF,0,@varOut) = #S_OK
            MarkupPointerS2\Release()
          EndIf ; If MarkupPointerS2
          MarkupPointerS1\Release()
        EndIf ; If MarkupPointerS1
        Element\Release() 
      EndIf ; If TextRange\parentElement(@Element.IHTMLElement) = #S_OK And Element 
      MarkupServices\Release()
    EndIf ; If MarkupServices
    TextRange\Release() 
  EndIf ; If TextRange
  ProcedureReturn Result
EndProcedure

To use the PasteHTML command you must do something as:

Code: Select all

Procedure.s PutHTMLCodeAtCaretPos(WebGadget,HTMLCode$) ; by Zapman
  WebGadget_Exec(WebGadget,#OLECMDID_DELETE,#OLECMDEXECOPT_DODEFAULT,0,0) ; this line is necessary because PasteHTML doesn't always erase completely the old content (that's one of the IE bugs)
  TextRange.IHTMLTxtRange = GetTxtRange(WebGadget)
  If TextRange
    bstr = StringToBStr (HTMLCode$)
    TextRange\PasteHTML(ReadBSTR(bstr))
    SysFreeString_(bstr)
    TextRange\Release()
  EndIf
EndProcedure
Because of all the problems I got precedently, I'm not really confident with this PastHTML command. I'll test it.

Be strong, boy, the way is long!![/code]
Don't try - DO it !
Dare
Addict
Addict
Posts: 1965
Joined: Mon May 29, 2006 1:01 am
Location: Outback

Post by Dare »

Hi zapman*,

lol, some good humour in your post! And as you're also struggling with this my 2 brain cells are feeling a little better about themselves.

Thanks for the code, I'll have a go with it.

I had a thought (dangerous thing to have happen). With my online wysiwyg code (dom, js) I can load another webpage, ctrl-A (select all), ctrl-c (copy), set the focus and insertion point on the wysiwyg and ctrl-P (paste). Inserts everything.

So ... I am going to try having a hidden 2nd webgadget, writing the insert stuff to that, copying to clipboard and then pasting to the main webgadget from the clipboard.

But all this tomorrow, currently have some other stuff to do.

Thanks for the help!
Dare2 cut down to size
User avatar
Kwai chang caine
Always Here
Always Here
Posts: 5494
Joined: Sun Nov 05, 2006 11:42 pm
Location: Lyon - France

Post by Kwai chang caine »

Hello at all

What a very great code 8)
That's exactely what i search for a long time ago. :D
Congratulation at the creator 8)

But i have a problem.
This code don't work whith all internet page :(
I tested it whith "http://www.google.fr" and it not run :(

For example the function FindInWebGadget() work fine with http://www.purebasic.com and don't work with "http://www.google.fr".

Il somebody know why ? :roll:
Is it my fault ? :oops:

Thanks.
ImageThe happiness is a road...
Not a destination
Post Reply