<commit_before>"
I am PjBrowserProxy and I provide a Pharo-side proxy for browser-side Javascript objects.

I provide access to Javascript and DOM objects on the browser.
Messages sent to my instances will evaluate on the browser allowing creation and manipulation of Javascript and DOM objects.
This allows development and debugging of programs on Pharo (using the browser as the UI) for subsequent deployment on the browser.

I should become a subclass of ProtoObject, but there are things to be done first, such as implement isNil, the ifNil:s, class, inspect, Nautilus support methods, etc.  In the meantime, if there is a method that should go to the browser, define it like #confirm:

My class has a reference to a PjBrowserBridge which has a connection to the browser so that I can execute code on the browser.

Example: 

1) highlight and do: "" PjProxy startOn: 12345 ""

2) now in a browser open localhost:12345

3) in a Playground, you can now access ""window"", ""document"" (but you cannot do it in the same playground as the startOn:)

4) When you are finished do: "" PjProxy stop ""

Public API and Key Messages

- startOn: - class method to create a port for connection from a browser 
- stop - class method to end the connection

The values window and document are pre-defined PjBrowserProxy  objects.
Any message sent to a PjBrowserProxy object will execute on the browser and return a Smalltalk value - either a primitive value or a PjBrowserProxy object.
  
Internal Representation and Key Implementation Points.

    Class Variables
	bridge:		<PjBrowserBridge> - connection to the browser

    Instance Variables
	jsName:		<String> - browser-side name of the value


    Implementation Points

- finalization of the Smalltalk object deletes the cached value on the browser

"
Class {
	#name : #PjProxy,
	#superclass : #Object,
	#instVars : [
		'jsName',
		'closure',
		'proxySpecificBridge'
	],
	#category : #'PharoJsBridge-Proxy'
}

{ #category : #'instance creation' }
PjProxy class >> newProxyNamed: proxyName onBridge: aBridge [
	^ ((proxyName beginsWith: '$_') ifTrue: [ PjProxy ] ifFalse: [ PjProxyForGlobal ]) new
		jsName: proxyName onBridge: aBridge;
		yourself
]

{ #category : #'instance creation' }
PjProxy class >> nilOrProxyNamed: proxyName onBridge: aBridge [
	proxyName = #undefined
		ifTrue: [ ^ nil ].
	proxyName = #null
		ifTrue: [ ^ nil ].
	^ self proxyNamed: proxyName onBridge: aBridge
]

{ #category : #'instance creation' }
PjProxy class >> proxyNamed: proxyName onBridge: aBridge [
	aBridge ifNotNil: [
		aBridge proxies at: proxyName ifPresent: [: proxy |
			proxy ifNotNil: [
				^ proxy
		]].
		^ aBridge proxies at: proxyName put: (PjProxy newProxyNamed: proxyName onBridge: aBridge)
	].
	^ PjProxy newProxyNamed: proxyName onBridge: aBridge
]

{ #category : #comparing }
PjProxy >> = anObject [
	super == anObject ifTrue: [ ^ true ].
	(anObject isKindOf: PjProxy) ifFalse: [ ^ false ].
	jsName = anObject asJSON ifFalse: [ ^ false ].
	proxySpecificBridge ifNil: [ ^ true ].
	anObject jsBridge ifNil: [ ^ true ].
	^ proxySpecificBridge = anObject jsBridge
]

{ #category : #'reflective operations' }
PjProxy >> addEventListener: type block: listener [
	| jsMessage |
	^ self jsBridge: [ :bridge | | bc |
		bc := bridge blockClosure: listener.
		jsMessage := PjJavascriptMessage receiverId: bridge websocketDelegateClassName selector: #set:callback:to: arguments: { self. type. bc }.
		bridge evalMessage: jsMessage
	]<commit_msg>Fixed proxy to avoid infinite loop caused by the new implementation of WeakDictionary that sends value to the retrieved object<commit_after>"
I am PjBrowserProxy and I provide a Pharo-side proxy for browser-side Javascript objects.

I provide access to Javascript and DOM objects on the browser.
Messages sent to my instances will evaluate on the browser allowing creation and manipulation of Javascript and DOM objects.
This allows development and debugging of programs on Pharo (using the browser as the UI) for subsequent deployment on the browser.

I should become a subclass of ProtoObject, but there are things to be done first, such as implement isNil, the ifNil:s, class, inspect, Nautilus support methods, etc.  In the meantime, if there is a method that should go to the browser, define it like #confirm:

My class has a reference to a PjBrowserBridge which has a connection to the browser so that I can execute code on the browser.

Example: 

1) highlight and do: "" PjProxy startOn: 12345 ""

2) now in a browser open localhost:12345

3) in a Playground, you can now access ""window"", ""document"" (but you cannot do it in the same playground as the startOn:)

4) When you are finished do: "" PjProxy stop ""

Public API and Key Messages

- startOn: - class method to create a port for connection from a browser 
- stop - class method to end the connection

The values window and document are pre-defined PjBrowserProxy  objects.
Any message sent to a PjBrowserProxy object will execute on the browser and return a Smalltalk value - either a primitive value or a PjBrowserProxy object.
  
Internal Representation and Key Implementation Points.

    Class Variables
	bridge:		<PjBrowserBridge> - connection to the browser

    Instance Variables
	jsName:		<String> - browser-side name of the value


    Implementation Points

- finalization of the Smalltalk object deletes the cached value on the browser

"
Class {
	#name : #PjProxy,
	#superclass : #Object,
	#instVars : [
		'jsName',
		'closure',
		'proxySpecificBridge'
	],
	#category : #'PharoJsBridge-Proxy'
}

{ #category : #'instance creation' }
PjProxy class >> newProxyNamed: proxyName onBridge: aBridge [
	^ ((proxyName beginsWith: '$_') ifTrue: [ PjProxy ] ifFalse: [ PjProxyForGlobal ]) new
		jsName: proxyName onBridge: aBridge;
		yourself
]

{ #category : #'instance creation' }
PjProxy class >> nilOrProxyNamed: proxyName onBridge: aBridge [
	proxyName = #undefined
		ifTrue: [ ^ nil ].
	proxyName = #null
		ifTrue: [ ^ nil ].
	^ self proxyNamed: proxyName onBridge: aBridge
]

{ #category : #'instance creation' }
PjProxy class >> proxyNamed: proxyName onBridge: aBridge [
	|proxy|
	aBridge ifNotNil: [
		proxy := aBridge proxies at: proxyName ifAbsent: [nil].
		proxy ifNotNil: [^ proxy].
		proxy := PjProxy newProxyNamed: proxyName onBridge: aBridge.
		^aBridge proxies at: proxyName put: proxy.
	]

]

{ #category : #comparing }
PjProxy >> = anObject [
	super == anObject ifTrue: [ ^ true ].
	(anObject isKindOf: PjProxy) ifFalse: [ ^ false ].
	jsName = anObject asJSON ifFalse: [ ^ false ].
	proxySpecificBridge ifNil: [ ^ true ].
	anObject jsBridge ifNil: [ ^ true ].
	^ proxySpecificBridge = anObject jsBridge
]

{ #category : #'reflective operations' }
PjProxy >> addEventListener: type block: listener [
	| jsMessage |
	^ self jsBridge: [ :bridge | | bc |
		bc := bridge blockClosure: listener.
		jsMessage := PjJavascriptMessage receiverId: bridge websocketDelegateClassName selector: #set:callback:to: arguments: { self. type. bc }.
		bridge evalMessage: jsMessage
	]
{'fraction_non_alphanumeric': 0.08229107447413303, 'fraction_numerical': 0.003979533826037522, 'mean_word_length': 4.271161048689138, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7469268', 'n_tokens_mistral': 2189, 'n_tokens_neox': 2033, 'n_words': 864}