Customising the app

Exposed functionality under extension framework

We have exposed a set of functions and getters under a proxy which can be used to access data, config and trigger events. Below is a list and how to access them.

interface EventData {
  key?: string,
  keys?: string[]
  view?: any,
  next?: any,
  error?: any,
  completed?: any,
  id?: any
}

* getValue(key)
* setValue(key, value)
* subject // getter
* subscribe(opts: EventData)
* subscribeAppEvent(opts: EventData)
* subscribeAppModel(key, next)
* subscribeParentEvent(opts: EventData)
* parentEventHandlerNext(eventName: string, opts: any)
* appModelNext(eventName:string, opts)
* appEventHandlerNext(eventName:string, opts)
* next(eventName:string, opts, eventHandler?)
* viewConfig //getter
* args //getter

Our app follows a MVC (Model, View, Controller) structure

Model

The model defines the various attributes and store their values. The values of the various attributes stored in the model can be accessed from the controller using the syntax

this.getValue('attributeName')

For customisation in the app, all newly created attributes will be added under a map in the model.
To set a new attribute in the model we will use the following syntax in the controller:

// If a key is not already in model then it will be added to extraProps
this.setValue('key', value)

To access an attribute added to the model we will use the following syntax:

const value = this.getValue("key")

View

The view defines the UI of the app. We use JSON files to define the view of our files. Here, we define the components, the css (as given in the extraclass of components) and render the values stored in the model.
In our app, each view is defined using a JSON. The JSONs are referenced using their unique IDs called a id.

Controller

The controller is used to handle events and process the data. The controller is used to fetch and send data from the server, it is the interface between what is displayed on the UI and stored on the backend.

  • To set values at initialisation, we use the init function.
  • To add a method the the controller we use the following syntax:
methodName: function(args){
    // functionality
}

The methodName here serves as the key to reference the method in the JSON (view) or in other functions

  • To call a method in the controller we use the syntax
this.next('methodName', args)

Example

Let us now use a simple example to show how these 3 components interact with each other.
We will add a button which switches its label value on a click

View Example

Below we define the JSON for a button that shows a dynamic text stored in the model under the variable name buttonLabel.
In this example, clicking the button changes its label.

{
    "component": "button",
    "label": "@extraProps.buttonLabel",
    "variant": "cta",
    "on-click": "switchButtonLabel",
}

Model Example

in this case, extraProps.buttonLabel holds the label of the button

Controller Example

  controller: {
    init: function () {
      this.setValue("buttonLabel", "Submit")
    },

    switchButtonLabel(){
        const buttonLabel = this.getValue("buttonLabel") === "Submit"? "Cancel" : "Submit"
        this.setValue("buttonLabel", buttonLabel)
    }
  }

Below GIF shows the above code in action
basic_customisation

View config example

In this case we access search mode event using viewConfig and trigger an event to update it

  {
    id: 'repository_panel',
    controller: {
      init: function () {
        console.log('Logging view config ', this.viewConfig)
        this.next(this.viewConfig.items[1].searchModeChangedEvent, { searchMode: true })
      }
    }
  }

Subscribe example

In this case we add subscription on file rename to console log when file rename option is clicked

  {
    id: 'repository_panel',
    controller: {
      init: function () {
        this.subscribe({
          key: 'rename',
          next: () => { console.log('rename using extension') }
        })
      }
    }
  }

Subscribe app event example

In this case we console log on active document changed (changing tabs in editor UI)

  {
    id: 'repository_panel',
    controller: {
      init: function () {
        this.subscribeAppEvent({
          key: 'app.active_document_changed',
          next: () => { console.log('Extension: active document changed') }
        })
      }
    }
  }

Subscribe app model events example

Example for subscribing app model events such as app.mode

  {
    id: 'repository_panel',
    controller: {
      init: function () {
        this.subscribeAppModel('app.mode',
          () => { console.log('app mode subs') }
        )
      }
    }
  }

Parent controller events example

In this we add subscription on tabChange event which is an event of left_panel_container controller which acts
as parent controller for repository_panel

  {
    id: 'repository_panel',
    controller: {
      init: function () {
        this.subscribeParentEvent({
          key: 'tabChange',
          next: () => { console.log('tab change subs') }
        })
        this.parentEventHandlerNext('tabChange', {
          data: 'map_panel'
        )
      }
    }
  }

App model and app controller next

They can be directly triggered by knowing correct event to fire and its data

  {
    id: 'file_options',
    controller: {
      init: function () {
        this.appModelNext('app.mode', 'author')
        this.appEventHandlerNext('app.active_document_changed', 'active doc changed')
      }
    }
  }
recommendation-more-help
11125c99-e1a1-4369-b5d7-fb3098b9b178