Exception subclass: #JSException instanceVariableNames: 'jsError' classVariableNames: '' poolDictionaries: '' category: 'JSBridge-Core'! !JSException methodsFor: 'signalling' stamp: 'WRB 4/26/2020 09:11'! error: error jsError := error. self signal: error message! ! "-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- "! JSException class instanceVariableNames: ''! !JSException class methodsFor: 'as yet unclassified' stamp: 'WRB 4/26/2020 09:12'! error: jsError JSException new error: jsError! ! Object subclass: #JSObjectProxy instanceVariableNames: '' classVariableNames: 'CallbackSemaphore CallbackProcess' poolDictionaries: '' category: 'JSBridge-Core'! !JSObjectProxy commentStamp: 'bf 07/12/2016 21:05' prior: 0! A JSObjectProxy is a proxy for JavaScript objects. It intercepts messages to look up named properties, and call them if they are functions. Arguments are converted from Squeak to JavaScript objects for nil, Booleans, SmallIntegers, Floats, Strings, Arrays, and Dictionaries. The result is converted back to Squeak objects for numbers and null/true/false, otherwise wrapped in a new JSObjectProxy. To add new properties, or access existing properties without calling them (if they are functions), use at:/at:put:. In addition, sending #new/#new:... creates an instance of that object, and #typeof returns the type as a string. There is a global proxy named JS to allow accessing global JavaScript objects. "Call global function" JS alert: 'Squeak says Hello World!!'. "Call function on global object (open console to see result)" JS console log: 'Squeak says Hello World!!'. "Modify DOM" | h1 | h1 := JS document createElement: 'h1'. h1 innerHTML: 'Hello World!!'. h1 style: 'position: absolute; color: blue'. JS document body append: h1. "Create new Object, add properties and a method, retrieve property, call method" | obj | obj := JS Object new. obj at: #someProp put: 42. obj at: #complexProp put: {#a -> 3. #b -> 4}. obj at: #someMethod put: (JS Function new: 'return this.complexProp.a + this.complexProp.b'). {obj someProp. obj complexProp. obj someMethod} "Inspect all properties in global window object" | object propNames propValues | object := JS window. propNames := JS Object keys: object. propValues := (0 to: propNames length - 1) collect: [:i | (propNames at: i) -> (object at: (propNames at: i))]. (propValues as: Dictionary) inspect "A Squeak block becomes a JavaScript function" JS at: #sqPlus put: [:arg0 :arg1 | Transcript show: 'sqPlus called with ', arg0 asString, ' and ', arg1 asString; cr. arg0 + arg1]. "It can be called from JavaScript (open transcript to see)" JS eval: 'sqPlus(3, 4)'. "It returns a Promise. When resolved, you can access the result" JS eval: 'sqPlus(3, 4).then(function(result) { console.log(result); })'. "Which even works from Squeak ..." (JS sqPlus: 3 and: 4) then: [:result | JS alert: result]. "But instead of using JavaScript's then() function, you can use Smalltalk's semaphores!!" JS await: (JS sqPlus: 3 and: 4). "If you don't need a result, just ignore the Promise" JS setTimeout: [JS alert: 'Hi'] ms: 1000. "Now for some fun: Load jQuery, and compile a helper method" | script | (JS at: #jQuery) ifNil: [ script := JS document createElement: 'SCRIPT'. script at: 'src' put: 'https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'. script at: 'type' put: 'text/javascript'. ((JS document getElementsByTagName: 'head') at: 0) appendChild: script. ]. String compile: 'asJQuery ^JS jQuery: self' classified: '*mystuff' notifying: nil. "Use jQuery" 'canvas' asJQuery hide: 'slow'; show: 'fast'. 'h1' asJQuery css: {'color'->'red'. 'text-shadow' -> '0 2px white, 0 3px #777'}. '