Skip to content

Custom Sheet Views ‐ Tutorial

c-g-dev edited this page Oct 11, 2024 · 1 revision

Custom Sheet View Schema

// SheetView is an abstraction for an object which creates/manages the custom sheet view element
interface SheetView {
    function getElement(): Element;
}

//row-level information passed to the handler
typedef SheetViewContext = {
    var sheet: Sheet; //this sheet
    var rowIndex: Dynamic; //index of the row in the sheet
    var row: Dynamic; //the row object in the database
    var sheetView: SheetView; //this SheetView
    var handler: SheetViewHandler; //this handler
}

typedef SheetViewHandler = {
    var definition: {
        name: String, //sheet type name, e.g "Level"
        schema: Array<{n: String, t: ColumnType}> //the columns which are prepopulated
    };
    function render(context: SheetViewContext): SheetView; //create and return the SheetView
    function toRowObject(context: SheetViewContext): Promise<Dynamic>; //write the information in the GUI control back to a database row
    var ?onClose: (SheetViewContext) -> Promise<Void>; //optional clean-up
}

Example: FabricJS Canvas Renderer

Define the SheetView

// SheetView
var DrawingCanvasSheetView: SheetView = (context) -> {
    var iframe: IFrameElement = Browser.document.createElement('iframe');
    iframe.style.border = 'none';
    iframe.width = '800';
    iframe.height = '600';

    // Set the iframe content
    iframe.srcdoc = '''
    <!DOCTYPE html>
    <html>
    <head>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/5.3.0/fabric.min.js"></script>
    </head>
    <body>
        <canvas id="canvas" width="800" height="600"></canvas>
        <script>
            var canvas = new fabric.Canvas('canvas');
            // Expose canvas to the parent window
            window.canvas = canvas;
        </script>
    </body>
    </html>
    ''';

    return {
        getElement: () -> iframe,
        getCanvas: () -> new Promise((resolve, reject) -> {
            iframe.onload = () -> {
                var canvas = iframe.contentWindow.canvas;
                if (canvas != null) {
                    resolve(canvas);
                } else {
                    reject('Canvas not found');
                }
            };
        })
    };
};


// SheetViewHandler
var DrawingCanvasSheetHandler: SheetViewHandler = {
    definition: {
        name: "Drawing Canvas Sheet",
        schema: [
            { n: "id", t: ColumnType.TString },
            { n: "drawingData", t: ColumnType.TString },
        ]
    },
    render: (context) -> {
        return DrawingCanvasSheetView(context);
    },
    toRowObject: (context) -> {
        return context.sheetView.getCanvas().then((canvas) -> {
            var data = canvas.toJSON();
            var rowData = {
                id: context.row.id,
                drawingData: Json.stringify(data)
            };
            return rowData;
        });
    },
    onClose: (context) -> {
        // Any cleanup if necessary
        return Promise.resolve();
    }
};

Registering the SheetViewHandler

You can wrap a SheetViewHandler as an hscript plugin which can be directly dropped in the /plugins folder:

typedef Plugin = {
	var type:String;
	var ?name:String;
}

typedef SheetViewPlugin = Plugin & SheetViewHandler;

Then, inside your plugin file:

// SheetViewPlugin
var DrawingCanvasSheetPlugin: SheetViewPlugin = {
    //...everything from the above example
    type: "SheetViewPlugin",
    name: "FabricJSSheetPlugin"
};

var export = DrawingCanvasSheetPlugin;

Alternatively, if you are building from source, you can directly register your custom sheet handler with the SheetViewManager at compilation time.

SheetViewManager.register(MyCustomSheetHandler);

Clone this wiki locally