'From Moshi of 3 March 2007 [latest update: #276] on 25 September 2007 at 3:33:44 pm'! "Change Set: JSWorkspace Date: 25 September 2007 Author: Takashi Yamamiya A workspace for javascript. - better error handling, world menu (9/25). - cmd+i in list pane. - You can set global object with JSWorkspace >> global: - using printString() - support cmd+d, cmd+i, cmd+p (dirty hack version). (JSInspector openOn: (JSObject eval: 'obj = {one: ""first"", two: 2}')) openInWorld. "! ValueHolder subclass: #JSWorkspace instanceVariableNames: 'object global' classVariableNames: '' poolDictionaries: '' category: 'Javascript-Tools'! !JSWorkspace commentStamp: 'tak 9/17/2007 22:32' prior: 0! This is a programming tool like Smalltalk Workspace for JavaScript. JSWorkspace new open (JSWorkspace global: EJSObject global makeSandbox) open Structure: object JSObject -- Javascript environment ! JSWorkspace subclass: #JSInspector instanceVariableNames: 'target selectionIndex fieldList' classVariableNames: '' poolDictionaries: '' category: 'Javascript-Tools'! !JSInspector commentStamp: 'tak 9/12/2007 20:37' prior: 0! Besides basic workspace feature, it provides a user interface to access each key in the target object. (JSInspector openOn: (JSObject eval: 'obj = {one: "first", two: 2}')) openInWorld. (JSObject eval: 'new Object()') jsInspect. JSObject global makeSandbox jsInspect Structure: target JSObject -- target object selectionIndex Integer -- Current selection in the field list. fieldList Array -- A cache of all key names in the target object. ! !Object methodsFor: 'user interface' stamp: 'tak 9/11/2007 21:19'! jsInspect (JSInspector openOn: self) openInWorld! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/12/2007 20:34 < tak 9/10/2007 21:47'! acceptContents: aString self contents: aString asString. ^ true! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/12/2007 21:54'! doIt: pluggableTextMorph | aString editor | pluggableTextMorph handleEdit: [editor _ pluggableTextMorph textMorph editor. editor lineSelectAndEmptyCheck: [^ '']. aString _ editor selectionAsStream upToEnd. ^ self eval: aString]! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/17/2007 22:29'! eval: aString ^ global class eval: aString withGlobal: global! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/17/2007 22:30'! global: aJSObject global := aJSObject! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/12/2007 20:34 < tak 9/11/2007 21:14'! inspectIt: pluggableTextMorph (self doIt: pluggableTextMorph) jsInspect! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/12/2007 21:53'! modelKeyStroke: evt on: pluggableTextMorph evt commandKeyPressed ifFalse: [^ false]. evt keyCharacter = $d ifTrue: [self doIt: pluggableTextMorph. ^ true]. evt keyCharacter = $i ifTrue: [self inspectIt: pluggableTextMorph. ^ true]. evt keyCharacter = $p ifTrue: [self printIt: pluggableTextMorph. ^ true]. ^ false! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/19/2007 16:39'! printIt: pluggableTextMorph | result | result := self doIt: pluggableTextMorph. pluggableTextMorph handleEdit: [pluggableTextMorph textMorph editor afterSelectionInsertAndSelect: (self printStringFor: result ifError: [:e | ''])]! ! !JSWorkspace methodsFor: 'accessing' stamp: 'tak 9/19/2007 16:30'! printStringFor: aJSObject ifError: aBlock ^ [aJSObject jsSend: #printString withArguments: #()] on: Error do: [:e | aBlock value: e ]! ! !JSWorkspace methodsFor: 'control' stamp: 'tak 9/12/2007 20:34 < tak 9/10/2007 21:48'! codePaneMenu: aMenu shifted: shifted "Note that unless we override perform:orSendTo:, PluggableTextController will respond to all menu items in a text pane" | donorMenu | donorMenu _ shifted ifTrue: [ParagraphEditor shiftedYellowButtonMenu] ifFalse: [ParagraphEditor yellowButtonMenu]. ^ aMenu labels: donorMenu labelString lines: donorMenu lineArray selections: donorMenu selections! ! !JSWorkspace methodsFor: 'control' stamp: 'tak 9/17/2007 22:12'! inspectorKey: aChar from: view aChar == $i ifTrue: [^ self inspectSelection]. aChar == $I ifTrue: [^ self exploreSelection]. aChar == $f ifTrue: [^ self followSelection]. aChar == $b ifTrue: [^ self browseMethodFull]. aChar == $h ifTrue: [^ self classHierarchy]. aChar == $c ifTrue: [^ self copyName]. aChar == $p ifTrue: [^ self browseFullProtocol]. aChar == $N ifTrue: [^ self browseClassRefs]. aChar == $t ifTrue: [^ self tearOffTile]. aChar == $v ifTrue: [^ self viewerForValue]. ^ self arrowKey: aChar from: view! ! !JSWorkspace methodsFor: 'control' stamp: 'tak 9/12/2007 20:34 < tak 9/10/2007 22:16'! perform: selector orSendTo: otherTarget selector = #doIt ifTrue: [^ self doIt: otherTarget]. selector = #inspectIt ifTrue: [^ self inspectIt: otherTarget]. selector = #printIt ifTrue: [^ self printIt: otherTarget]. ^ super perform: selector orSendTo: otherTarget! ! !JSWorkspace methodsFor: 'initialize-release' stamp: 'tak 9/17/2007 22:16'! initialize global := JSObject global makeSandbox! ! !JSWorkspace methodsFor: 'initialize-release' stamp: 'tak 9/17/2007 22:08'! open "self new open" | window | window _ (SystemWindow labelled: self name) model: self. window addMorph: (PluggableTextMorph on: self text: #contents accept: #acceptContents: readSelection: nil menu: #codePaneMenu:shifted:) frame: (0 @ 0 corner: 1 @ 1). ^ window openInWorld! ! !JSInspector methodsFor: 'initialize-release' stamp: 'tak 9/11/2007 22:09'! initialize selectionIndex := 0. fieldList := #()! ! !JSInspector methodsFor: 'initialize-release' stamp: 'tak 9/17/2007 22:16'! inspect: aJSObject target := aJSObject. global := JSObject global makeSandbox jsAt: #this put: aJSObject; yourself! ! !JSInspector methodsFor: 'menu' stamp: 'tak 9/11/2007 21:29'! fieldListMenu: aMenu aMenu addList: #(#('inspect (i)' #inspectSelection) ). aMenu addList: #(#('basic inspect' #inspectBasic) ). ^ aMenu! ! !JSInspector methodsFor: 'menu' stamp: 'tak 9/11/2007 21:53'! inspectBasic self selection inspect! ! !JSInspector methodsFor: 'menu' stamp: 'tak 9/11/2007 21:35'! inspectSelection self selection jsInspect! ! !JSInspector methodsFor: 'menu' stamp: 'tak 9/11/2007 21:36'! perform: selector orSendTo: otherTarget selector == #inspectSelection ifTrue: [^ self inspectSelection]. selector == #inspectBasic ifTrue: [^ self inspectBasic]. ^ super perform: selector orSendTo: otherTarget! ! !JSInspector methodsFor: 'menu' stamp: 'tak 9/17/2007 22:20'! selection selectionIndex = 0 ifTrue: [^ target]. ^ target jsAt: (fieldList at: selectionIndex)! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/12/2007 21:55'! accept: aString | result | result _ self eval: aString. target jsAt: (fieldList at: selectionIndex) put: result. self toggleIndex: selectionIndex. ^ true! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/12/2007 21:58'! eval: aString | result | result _ super eval: aString. self changed: #fieldList. ^ result! ! !JSInspector methodsFor: 'accessing' stamp: 'aw 9/12/2007 11:32'! fieldList ^ fieldList := target jsKeys asArray! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/11/2007 21:06'! initialExtent ^ 250 @ 200! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/11/2007 18:31'! selectionIndex ^ selectionIndex! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/19/2007 17:01'! selectionName | name key | name := self selectionIndex = 0 ifTrue: ['this'] ifFalse: [key := fieldList at: selectionIndex. key isNumber ifTrue: ['this[' , key asString , ']'] ifFalse: ['this["' , key asString , '"]']]. ^ self printStringFor: self selection ifError: [:e | '']! ! !JSInspector methodsFor: 'accessing' stamp: 'tak 9/19/2007 16:36'! toggleIndex: anInteger selectionIndex _ anInteger. contents _ self selectionName. self changed: #contents. self changed: #selectionIndex. self changed: #selection! ! !JSWorkspace class methodsFor: 'instance creation' stamp: 'tak 9/17/2007 22:31'! global: aJSObject ^ self new global: aJSObject; yourself! ! !JSWorkspace class methodsFor: 'instance creation' stamp: 'tak 9/25/2007 11:29'! open ^ self new open! ! !JSWorkspace class methodsFor: 'class initialization' stamp: 'tak 9/25/2007 11:30'! initialize TheWorldMenu registerOpenCommand: {'Javascript Workspace'. {JSWorkspace. #open}. 'a javascript workspace'}! ! !JSInspector class methodsFor: 'instance creation' stamp: 'tak 9/11/2007 18:20'! inspect: aJSObject ^ self new inspect: aJSObject! ! !JSInspector class methodsFor: 'instance creation' stamp: 'tak 9/19/2007 16:35'! openOn: aJSObject | inspector window listPane valuePane evalPane | inspector _ self new inspect: aJSObject. window _ (SystemWindow labelled: inspector selectionName) model: inspector. listPane _ PluggableListMorph new doubleClickSelector: #inspectSelection; on: inspector list: #fieldList selected: #selectionIndex changeSelected: #toggleIndex: menu: #fieldListMenu: keystroke: #inspectorKey:from:. valuePane _ PluggableTextMorph on: inspector text: #contents accept: #accept: readSelection: nil menu: #codePaneMenu:shifted:. evalPane _ (PluggableTextMorph on: inspector text: #trash accept: #trash: readSelection: nil menu: #codePaneMenu:shifted:) askBeforeDiscardingEdits: false. window addMorph: listPane frame: (0 @ 0 corner: 0.3 @ 0.7). window addMorph: valuePane frame: (0.3 @ 0 corner: 1 @ 0.7). window addMorph: evalPane frame: (0 @ 0.7 corner: 1 @ 1). window setUpdatablePanesFrom: #(#fieldList ). window position: 16 @ 0. inspector toggleIndex: 0. "Room for scroll bar." ^ window! ! !TextMorphForEditView methodsFor: 'event handling' stamp: 'tak 9/12/2007 21:44'! keyStroke: evt | view | (editView scrollByKeyboard: evt) ifTrue: [^self]. ((editView model respondsTo: #modelKeyStroke:on:) and: [editView model modelKeyStroke: evt on: editView]) ifTrue: [^self]. self editor model: editView model. "For evaluateSelection" view _ editView. "Copy into temp for case of a self-mutating doit" (acceptOnCR and: [evt keyCharacter = Character cr]) ifTrue: [^ self editor accept]. super keyStroke: evt. view scrollSelectionIntoView! ! JSWorkspace initialize!