Script Library: 1238 scripts
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Archive version of: rebol-dom.r ... version: 49 ... inetw3dm 27-May

Amendment note: Updated: Methods and linked lists: think Lua. (tables); || Publicly available? Yes

REBOL [
    	File: %rebol-dom.r
    	Date: 05-01-2021
    	Title: "Dialect Object Model"
        Emai: inetw3.dm@gmail.com
        author: daniel murrill
    	Purpose: {
             Use a recodable rebol function to create easy to follow blocks/series as 
             a Dialect Object Model  that allow different program languages to work together
             and viewed as HTML and VID. A parse alternative}
    	]

library: [
        author: daniel murrill
    	level: 'intermediate
        platform: 'all
        type: Dialect
        domain: [html vid css json js array]
        tested-under: 'windows
        support: none
        license: none
        see-also: %Mdlparser.r
        version: 0.9
    ]

my-dialect: [

rebol-DOM: [{DSL-type="html/block" type="text/html"}]

lua-tbl = {[first] = "fred", [last] = "cougar"} 
    
#this-issue [{color: "purple" bgcolor: "orange"}]

var anObj = { 100: 'a', 2: 'b', 7: 'c', };

body: [{background-color="blue" text "white"} ]

p: [
    { "color":"#0000ff", "bgcolor":"yellow", "width" : "399", "height" : "100" "font-styles": "big" } 
 This is an example of an Dialect Oject Model
b: [
    {color = "Chocolate" bgcolor = "yellow"} 
    
 that can be written to look like json' html' javascript arrays' css'  
i: [
    {color = "green"} 
    
 VID' or plain old rebol ] 
  ] 
 if you like.
  ]


hr: [{color="red" bgcolor="yellow"}]

div: [
    {width="399" bgcolor="orange"}  
b: [
    {color: "purple" bgcolor: "orange"} 
    
 Maybe it would be easier to write  
i: [
    {color: "green"}
    
 MakeDoc.r code but the purpose of this rebol DOM is']  
   ]
]

p: [
    {width "399" height= 200 
    style="color: red;  bgcolor: brown; border: 2x2;" 
    } 
b: [     
    {color="red"}
 to read or load as many well known dialects of coding styles as possible
 and write all of it as a single or seperate legible rebol series that's
 quickly manipulated' transcoded as html' and viewed as a VID. ]
  ]



]


document.: func [request-as][
		DOM: head DOM use*=*to-set-values 
		any [equal? block! type? data-node data-node: node: reduce [to-block data-node]]
		either equal? tag! type? data-node/1 [node-element: data-node/1
		][
		node-element: data-node/1: build-tag to-block first parent-node: data-node
		]
		var .style: = node-element style: :array-obj! .style: :array-obj!
                return node-element
]
				
return-tag-node: does [=: :equal? 
		any [equal? block! type? data-node 
		data-node: node: reduce [to-block strip-obj-chars-from data-node]]
		any [equal? tag! type? node-element: data-node/1 attempt [
		replace/all node-element [=] [] 
		node-element: data-node/1: build-tag to-block node-element]
	]
]
 
.style: []
equal?: :=
DOM: DSL: html: window: end-tag: ""
data-node: parent-node: node: none

.body: .hr: .p: .b: .i: .tr: .ul: .li: .area: .table: .td: .button: .input: .div: .font: .span: 0
node-obj: node-element: node-name: *name: use-methods: attr-name: attr-value: none

check: func [select-this][return first parse select-this none]

strip-chars-from: func [node-name][
		foreach char elemt-chars: ["{" "}" "(" ")" {"} "/" "." "[" "]" "," ":" ";" "," "="
		][
		replace/all node-name char " "
		]	
]

strip-obj-chars-from: func [node-name][
		trim node-name if equal? #"^"" node-name/1 [remove node-name]
		foreach [-char +char] obj-chars: [#"^/" " " 
		"," "" {" : "} {: "} {":"} {: "} {":} {:} {" "} {" } { " } "" 
		"[" "" "]" "" {""} {"} {  "} "" ":" " " { =} {=} {=} " " "'" "" { #} { #","}
		][
		replace/all node-name -char +char
		]
]

getnodename: func [node-name][data-node: [""]
        DOM: head DOM =: :equal?
		either block! = type? node-name [
		insert/only data-node: [] node-name 
		any [attempt [node-element: data-node/1: build-tag data-node/1] node-element: data-node/1]
		][
		node-name: to block! strip-chars-from form node-name
		count: any [attempt [count: pick find node-name integer! 1]1]
		nodename: to-word join  "." array-obj!: node-name/1 
		any [repeat ? count [data-node: first DOM: next node: find DOM nodename]
		print reduce ["node-name:" mold form node-name/1 "not found"]
		]
		slf*: join node-name/1 count
		]
		if '= = first DOM [data-node: first next DOM]
		return either tag! = type? data-node/1 [node-element: data-node/1][node-element: data-node] 
]

setnodename: func [old-name new-name][
		any [equal? this-name: check strip-chars-from old-name check node-element getnodename old-name]
		any [equal? none not find node-element new-name try [
		replace node-element to string! this-name new-name 
		replace data-node to-tag join "/" this-name  to-tag join "/" new-name] 
		]		
]
 
getattribute: func [attr-name][
			attr-value: none
			do compose/deep [attr-value: array-obj![(attr-name)]]
			print any [[attr-name attr-value] ["node-attribute:" mold form attr-name "not found"]
			]
] 

setattribute: func [attr-name new-attr][
            *key: *value: none 
            do compose/deep [.style[(form attr-name )]]
            any [
            if *value [replace node-element attr-name new-attr]
            array-obj![repend [" " new-attr {="undefined"}]""]
            print ["Must get a parent-node with this attribute: " attr-name]]
			;get-attributes node-element attempt [set-attributes]
            ]		

setattributevalue: func [attr-name attr-value][
            any [
            if find node-element key: form attr-name [
			do compose/deep [.style[(key)] `= (attr-value)]]	
			array-obj![repend [" " attr-name {="}attr-value {"}]""]
			print ["Must get a parent-node with this attribute: " attr-name]
			] ;get-attributes node-element attempt [set-attributes]
]

getElementByTagName: func [Tag-Name selection [block!]][
            dom: head dom 
            repeat this first selection [
            node-element: first data-node: first dom: next find dom to-word join "." Tag-Name]
            if [use-methods and not find node-element " ."][use-attr-as-methods yes]
            use-methods: off        
]

look-deep-for: func [this in-node][
			foreach in-child-node in-node [
			if find/any mold node-element: in-child-node this [return node-element break]
			]
]

getElementById: func [my-id][in-child-node: none 
			id: copy join "id*" form my-id =: :equal?
			foreach in-parent-node dom [
		if block! = type? in-parent-node [any [look-deep-for id in-parent-node
			foreach in-sibling in-parent-node [
		if block! = type? in-sibling [look-deep-for id in-sibling 
			]]]]]
]

querySelecter: func [css-Selecter][in-child-node: none 
			id: rejoin [css-Selecter "*="] =: :equal?
			foreach in-parent-node dom [
		if block! = type? in-parent-node [any [look-deep-for id in-parent-node
			foreach in-sibling in-parent-node [
		if block! = type? in-sibling [look-deep-for id in-sibling 
			]]]]]
]

.innerHTML: func [element][
			children: copy/part next data-node find/last data-node tag!
			either equal? tag! type? node-element [
			any [empty? element replace data-node children element]
			][print "The node-element has no innerHTML"]
]
			
use*=*to-set-values: does [=: func [value][any [value]]]

use-attr-as-methods: func [maybe [logic!]][
			if maybe [foreach [-char +char][{" } {" .} ".." "."][replace/all node-element -char +char]
			]
			replace node-element " " " ."
			use-methods: yes
]

node-list: []

*!: func [var][set to-word check form node-element none set to-set-word form var :array-obj!]

var: func [var-data][node-element:  variable: "" node-name: :variable
			any [
			attempt [variable: first parse node-element: var-data "=:, "]
			attempt [if equal? block! type? var-data [variable: first node-element: var-data]] 
			attempt [variable: var-data node-element: ""]
			]
			use*=*to-set-values variable: to-string variable
			any [
			not empty? node-element any [find node-list variable append node-list reduce 
                        [variable node-element: any [attempt [do :variable] " "]]]] 
                        any [equal? tag! type? node-element append node-list reduce [form variable node-element]] 
                        set to-word variable array-obj!: func [key] node: compose/deep copy get-array-obj!
			attempt [if not find variable "." [do load to-string reduce ["set " #"'" variable ". :array-obj!"]]]
			use-methods: off
]

.: func [value][ do compose/deep reduce [*value reduce [(value)]]]

get-array-obj!: [
			if not equal? tag! type? node-element [node-element: select node-list  
                        (form variable) ] 
			if inline: find/any node-element { style*=*"} [
			replace node-element inline replace inline {"} " "]
			any [
                        if empty? form key [ 
                        return any [
                        if equal? tag! type? node-element [node-element]
			attempt [trim next find/tail node-element first parse node-element ":= ,"]
                        next node-element]
                        ]
			any [
			if find element: form key "@" [ 
			replace/all element "@" ":" node: parse/all element "." 
			*value: select node-element load node/1 
			remove node
			foreach element node [. load element]
			]			
			attempt [*value: load select parse strip-obj-chars-from copy node-element "[]{}`:;= " *key: form key]
			attempt [*value: select node-element *key: key] 
			]
                        attempt [do head insert next copy key [node-element join]] 
                        attempt [do form key] 
			if not find node-element key [none]] ;[print [*key "called"]]
]

`=: func[attr-value][
			any [
			attempt [replace node-element *value do reform load attr-value]
			replace node-element form *value form attr-value
			replace node-element mold form *value mold attr-value
			]
] 

node-element: *node-name: *name: array-obj!: key: *key: *value: ""

markup-DOM: func [DSL][
use-methods: string-is-data: no =: :equal?
		either block! = this-type?: type? DSL [
			DOM: copy/deep DSL: load replace/all replace/all mold DSL "__" " " {=""} {="undefined"}
			any [
			find DSL [rebol-DOM: [{DSL-type="html/block" type="text/html"}]]
			insert DSL [rebol-DOM: [{DSL-type="html/block" type="text/html"}]]]
			
			
get-data: func [data][	
		find-end-tag: find data get-word!
			either find-end-tag [
			replace data first find-end-tag  to-tag mold to-refinement first find-end-tag
			][
			insert tail data to-tag join "/" any [*name *node-name]
			]
repeat in-data data [
		if set-word! = type? in-data [*node-name: copy form in-data
			replace data in-data node-name: to-word join "." *node-name
			]
		if string! = type? in-data [
			strip-obj-chars-from in-data 
			insert in-data next reform [node-name " "]
			child: build-tag to-block in-data 
			foreach [a b][{=" } "={" {" "} "*}" "*" {"}][replace/all child a b]
			replace data in-data child
			]
		if block! = type? in-data [
			get-next in-data
			]
		]	 
]

get-next: func [in-data][
	repeat data in-data [
		if set-word! = type? data [*name: copy form data
			replace in-data data node-name: to-word join "." *name
			]
		if string! = type? data [
			strip-obj-chars-from data  
			insert data next reform [node-name " "]
			child: build-tag to-block data 
			foreach [a b][{=" } "={" {" "} "*}" "*" {"}][replace/all child a b]
			replace in-data data child
			]
		if block! = type? data [get-data data
			set to-word *node-name data]
		] find-end-tag: find in-data get-word!
			either find-end-tag[
			replace in-data first find-end-tag  to-tag mold to-refinement first find-end-tag
			][
			insert tail in-data to-tag join "/" any [*node-name *name]
			clear *node-name]
]

repeat with-this-data DSL [
		if issue! = type? with-this-data [
			node-name: to-word join "." *name: copy form with-this-data
			]
		if set-word! = type? with-this-data [
			replace DSL with-this-data node-name: to-word join "." *name: copy form with-this-data
			]
		if word! = type? with-this-data [
			either '= = with-this-data [string-is-data: yes replace DSL with-this-data ""
			][
			*name: copy form with-this-data
			replace DSL with-this-data node-name: to-word join "." with-this-data] 
			replace DSL reduce [node-name node-name] node-name
			]
		if string! = type? with-this-data [
			either string-is-data [
			replace DSL with-this-data rejoin [node-name " " with-this-data]
			][
			created-data: copy with-this-data
			strip-obj-chars-from created-data  
			insert created-data reduce [node-name " "]
			child: build-tag to-block remove created-data 
			foreach [a b][{=" } "={" {" "} "*}" "*" {"}][replace/all child a b]
			replace DSL with-this-data child
			]
			string-is-data: no
			]
		if block! = type? with-this-data [ 
			get-data with-this-data
			]
			
		if get-word! = type? with-this-data [
			replace DSL with-this-data to-tag mold to-refinement *name
			]
]
		    replace/all dsl "" [] DOM: copy DSL
	        ][
		    view center-face layout [
			backcolor black space 8
			across
			h3 yellow "Need a Dialect Object Model as type! block"
			return
			text gray "Your DSL type is: " text red bold form :this-type? 
			return
			text gray "Some DOM functions will not work properly"]
		    ]
		
]

format-this: func [node-element with-these-chars][
			foreach [-char +char] with-these-chars [
			replace/all node-element -char +char] 
			do last with-these-chars
]

as-js-object!: [
			{ #} "" 
			{="} {: "} "={" ": {" {""} {"} {" } {", } {", "} {"}
			[replace node-element " " ": {" 
			replace/all node-element { "} {: "}
			replace/all node-element "::" ":"
			replace/all node-element " : " ": "
			append node-element "}"]
]

.as-js-object: does [attempt [format-this node-element as-js-object!]]

return-html-dsl: does [
		html: copy form any [find head DOM "<body" head DOM]	
		replace/all replace/all html "<." "<" "' " ", "
		replace/all replace/all html "{" "<" "}" ">" 
		foreach n-name [
						".body " ".hr " ".p " ".b " ".i " ".? " 
						".tr " ".table " ".td " ".button " ".input "
						".div " ".ul " ".li " ".font " ".span "
						".img " ".a " ".strong " " ." ".hr " "lua-tbl "
						][replace/all html n-name " "
						]
		append replace/all html </body> "" </body>
		html: any [find html "<body" html]
]



markup-DOM my-dialect

getElementById 'my-p1
		
document. getnodename {"div"[1]}getattribute "bgcolor"  
    
document. getnodename{("p")[2]} .style[width] `= "block-build"

setattributevalue('height) "1000"
    
    node-element

    getattribute "height"

setnodename {hr[1]} "listview"

    node-element    
        
document. getnodename{("p")[1]}.style[font-styles] `= "block-build"
    
    setattribute('font-styles)"whithouse"
    
    setattributevalue('boogies)"green-color"

data-node: do to-path [DOM .p .b] 

document.(data-node).style[color] `= "bluberry" 

    setattribute('i-style) "silly" 
    

; Some examples of selecting keys and values set to variables as an array object.
; good to use with anything that's structured with {} , or "". It also can be used with [].
;IE (javascript, json objects/arrays.. lua table/arrays.. associative arrays etc.) 
;even DOM's and rebol data.

;The insert, remove, append, and lookup of a group (a node-element) by way of a Var (variable)
;is done as a data-node and syntactically as an associative array. The associattion of key 
;values is done by index in Rebol therefore there is no need for the overhead of objects or 
;multi.dim arrays. But the cool part is you can do what ever you like!

;You must use use*=*to-set-values before setting the first variable.
;it will use = to set any value to a variable (a set-word) 
;`= this literal equal is used to set values to keys. Feel free to use
;different function symbols for any !op function.  

use*=*to-set-values

;variables and there values (node-elements) that are'nt tags are sent and fetched from a
;node-list block for demo purposes. They will be appended to the DOM later.

;The variable name and the first word in it's value must be the same in order for
;the variable to be automatically bound to the node-element and array-obj!() function.



var hello: = {hello 100:"a" 2: "two words" 7="c"}

hello[2]

hello[2] `= "a to z"

node-element

;insert dots, "." to keys to be used as methods to get and set values.
;the to-methods function not created yet.sorry!.dot.

;use-methods: yes  

var app: = document.(getElementByTagName('p)[2]).style[bgcolor]`="green"
    
    .innerHTML("Lets change this, shall we.")


;You must call/associate the array-obj! with this variable name
;because the variable name "app" and the node-name/TagName "p"
;are not the same.

*![app] 

;or app: :array-obj!

;the style.obj! is auto created by using the document. function

.style["bgcolor"]

;is the same as calling, but without the cell(block) this time. 

app 'bgcolor

;Write values however. they are handled by the get-array-obj! as any-type.

node-element 

app[.width] `= "curly quew"

app ('bgcolor) `= to-string [purple]


;when you need to create a variable to use with an array-obj!


poppy: {100:"a" street : "backside" 7="c"}

var 'poppy ;local or global hoisting: must move to head.
head poppy[] 

var join {poppy2 } {200:"a" street : "backside" 7="c"}
poppy2[]


;you don't need a set-word! variable. It will always be the first
;word followed by ": =", ": ", or " " found in the value (node-element)
;or a set word that has a value.
;you can access it with array-obj![]. But the value will change once
;a new VAR is created and you'll have to select it from the node-list.

poppy[street]`="old rover rd."

poppy[7] `= "cities"

;VAR values can also be set to an arrayed object.

var poppy3: = [poppy3 #100:"a" street: "backside" #7:"c"]

;Even though it's not the best idea to use integers as keys, you can.
;it can encourage mistakes when trying to get by index...  poppy2[3]
;But this is Rebol, so we will roll with this...
;You must always start cell number keys with the pound sign. "#"

poppy3[street:]`= "old rover rd."

poppy3[#7:]`= "cities"

;DOM variables are renamed to start with a dot "." so not to be confused with words.
;this will change in the future. All DOM Var's will be type! set-word!.

;Remember when calling a node-name and using that name as the variable,

var .anObj: = getnodename "anobj"

;you dont have to call/associate the array-obj! with this variable name
;but the variable name must began with a dot. IE "."

.anobj[7]

;but with 

var anObj: = getnodename "anobj" 

;you do

*![anObj]  ;or anObj: :array-obj!
 
anobj[7]

;after calling some variable[key]/array-obj![key], you can replace the key and value.

replace replace node-element *key 'this-key *value {'some-value'}

data-node

var 'try-this 

try-this.[insert (add 50 50) ","]

node-element

try-this.[append ("new-value")","]

try-this[.innerHTML("change me please") ""]

;a roadmap for javascripting with the Dialect Object Model (DOM).

;A quick way to change op! functions between rebol and javascript.

js-op!: does [x: :* *: :do console.log: :print var 'use js-do: :js-op!] 
reb-op!: does [*: :x =: :equal? reb-do: :reb-op!]

;This code...

{
function welcomeSite() {
  siteMessage = "Welcome to the...";
  console.log(siteMessage);
  var siteMessage;
}
welcomeSite();

siteMessage.append("Rebolution") siteMessage
}

;Is changed to this code...

js-op!

'function! welcomeSite: *{
     siteMessage: = "Welcome to the... ";
     Message-type: "Welcome"
     do reb-op! alert(siteMessage)
     console.log(siteMessage);
     var 'siteMessage;
};


;Hey you can load welcomeSite from a DOM or files with variables, functions, key-values or Rebol code:

use[welcomeSite()];

;to use the welcomeSite Message-type in your code.

js-do 
*{
    var say-hi-to: = Message-type
    console.log(reduce ["This is a message to" say-hi-to "you."]);
  }
    
siteMessage.[append("Rebolution.")#"^/"] siteMessage.[print]

var first-obj: = {first-obj: first-name: "Brigsby" last-name: "Backfort"}

var second-obj: = {second-obj: first-name: "Krystal" last-name: "Frontbunker"}

first-obj[last-name]`="FortBack"  first-obj[]

second-obj[last-name]`="Bunkerfront"  second-obj[]

Var contacts: = {Bestfriend: "[{"first": "Besty", "last": "Bestest", "number": 777-9211}]"}

Bestfriend[first]   
*![contacts]
contacts[first]
;Does Var persist if not destroyed? YES.
first-obj[]


;and then back to Rebol

reb-do 2 * 2

;Create a DOM from a nested javascript object DSL, search and update.
;A return-js-object-dsl() function will return the new js-object.
;Mold blocks and load strings to do quick formating like remove all ",".
 
markup-DOM load replace/all {data: [
    fullName: "James Zhan",
    address: {
        city: "Shenzhen",
        state: {
            name: "Guangdone",
            abbr: "CN""
        },
        country: {
            local-name: "Guangdone",
            abbr: "CN"
			id: "jazzy"
        },
	},	
    hobbies: ["coding", "reading"],
    projects: [
        { name: "form2json", language: "javascript", popular: true },
        { name: "peony", language: "ruby" }
    ]
]
} "," ""

getElementById("jazzy").as-js-object

var here: dom/.data/.projects/1

*![here]

here[name]`="funkacopics" 

format-this node-element as-js-object!

node-element 

dom/.data/.address

;And a cool but very simple trick in Rebol. For non-rebolers
;this IS code and data mixed together. First it's ALL string data.

var num: {num: a: 1 b: 2 c: 3}
;Rember, the *num value is a string, not an object.
 
amount: num[a]`= [amount '+ 15]
;And the new *formed() value is a [string: "1" word: '+ integer: 15]

;The DO() function binds each piece to the interpreter, and voila!

num[a]



;And now Var methods with linked node-element lists, a mixture of object and arrays
;in a simple DSL keeping track of data updates with set limits. Don't try to undestand
;it, it's silly. 

;methods are written as messages sending or recieving. So lets use a form of
;urls and emails.

get-numbers@.has-a.variable-a ;or
get-numbers:.has-a.variable-a ; cause theres a set-word in there.

clear node-list

var check-if: = [
                check-if start: 'at-head 
                stop: 'at-tail 
                get-numbers: numbers  ;this is linked to local Var numbers
] 

var numbers: {
	numbers: 
		start-at: 1 
		has-a: limit  ;this is linked to local Var limit
		}

var limit: = {
		variable-a: "yes" 
		variable-b: "no"
		} *![limit]
	
	
	
numbers[start-at]

amount: numbers{start-at} `= {amount '+ 15}

increased: numbers[start-at]

do check-if[get-numbers:][increased]

;or

check-if.[get-numbers:].[start-at]


check-if.[get-numbers:].[has-a].[variable-a]

;place *fetch, "@" before or after any key. use it in place of the set/get-word #":"

check-if get-numbers@.has-a.variable-a

;And now get-numbers: , has-a, and variable-a becomes Var's once linked to
;only if they have following data.

variable-a('variable-b) "ok go ahead"
 
;A method is just putting the name of a Var in another Var as a key value pair.
;You don't need objects, parsers, classes, or tricked out functions to use your
;DSL's. To start you just look up or set everything by key value pairs.
;methods are just a quicker way to get to local associated data.