How-tos

Check also the File Manager How-to guides, because Document Manager is built upon this widget and can be customized in the same way.

Editing Excel files using Spreadsheet

You can edit Excel files using Spreadsheet.

Files to include

First of all you need to include Spreadsheet in your page:

<!-- spreadsheet js file -->
<script src="codebase/spreadsheet.js" type="text/javascript"></script>
<!-- spreadsheet css file -->
<link rel="stylesheet" type="text/css" href="codebase/spreadsheet.css">

Adding editor to UI

After that you need to define a new custom class and inherit it from the default one (docManager.views.excel). Inside the config() method we set the configuration for Spreadsheet and add it to the UI.

Adding Spreadsheet to UI

class Editor extends docManager.views.excel {
  config() {
    const ui = super.config();
    ui.rows[1].cols[0] = {
      view: "spreadsheet",
      localId: "editor",
      //...
    };
    return ui;
  }
}

To be able to track changes made by users we need to listen to the onChange event of Spreadsheet and call the ChangeTextState() method with true as the argument:

Tracking changes

class Editor extends docManager.views.excel {
  //...
    init() {
    // default logic
    super.init();
    // Spreadsheet has a different event to track changes
    this.on(this.$$("editor"), "onChange", () =>
      this.ChangeTextState(true)
    );
  }
}

After that don't forget to override the default class with the new one:

Overriding default class

webix.ui({
  view: "docmanager",
  url: "https://master--docmanager-go--dev.webix.io/",
  // overriding the default editor with the new one
  override: new Map([[docManager.views.excel, Editor]])
});

Saving files

To be able to save edited files you need to define a method to put all the saving logic in.

Custom method for saving

Save() {
  const editor = this.$$("editor");
  // stop editing and close the editor
  editor.$$("cells").editStop();
  return webix
    .toExcel(editor, {/* optional excel settings*/})
    .then(data => {
      return this.app
        .getService("operations")
        // replace old values with new ones
        .writeBinary(this.File.id, this.File.value, data);
      this.ChangeTextState(false);
    });
}

Readonly mode for Spreadsheet and additional diff logic

Spreadsheet has a different readonly setting and also requires a different logic for collecting and displaying cells with changes. First, you need to redefine the SetBatch method:

  • re-create Spreadsheet as readonly
  • collect diffs for each opened sheet and store them for later
SetBatch(batch) {
  this.getRoot()
    .queryView("toolbar")
    .showBatch(batch);
 
  // reinitting Spreadsheet with readonly:true
  this.Editor = webix.ui(
    {
      view: "spreadsheet",
      localId: "editor",
      bottombar: true,
      readonly: true,
    },
    this.$$("editor")
  );
  // attaching progress bar functionality
  webix.extend(this.Editor, webix.ProgressBar);
 
  // style diffs for a new opened sheet
  this.Editor.attachEvent("onAfterSheetShow", name => {
    if (this.Sheets && this.Sheets[name]) {
      // only for sheets that are opened 1st time
      if (!this.Sheets[name].diffs) {
        this.Sheets[name].diffs = this.CollectDiffs(
          this.Sheets[name].old,
          this.Sheets[name].new
        );
      }
      this.StyleDiffCells(this.State.diff, name);
    }
  });
}

Getting current version from history

To account for differences of API between default Excel editor and Spreadsheet and to support version history for several sheets, you need to redefine the ParseVersion method.

ParseVersion(v, diff) {
  if (v) {
    this.Editor.showProgress({ type: "top" });
  
    const path = this.app.getService("versions").directLink(v);
    const id = this.getSubView("r-side").GetPrevVersion(v);
 
    this.ResetTotalDiff(id ? false : diff);
 
    if (diff && id) {
      let prevPath = this.app.getService("versions").directLink(id);
      webix.promise
        .all([this.ParseExcel(prevPath), this.ParseExcel(path)])
        .then(res => {
          const older = res[0];
          const target = res[1];
 
          // store data for all sheets
          this.Sheets = this.GetSheetData(older, target);           this.Editor.parse(target, "excel");         });
    } else {
      // reset diffs for 1st version or if the 'diff' checkbox was unchecked
      this.Sheets = {};       this.Editor.load(`binary->${path}`, "excel").then(() => {
        this.Editor.hideProgress();
      });
    }
  }
}

Styling cells that were changed

For correct multiple sheet support, the StyleDiffCells must also be redefined:

StyleDiffCells(mode, sheet) {
  if (!sheet) sheet = this.Editor.getActiveSheet();
 
  // get collected diffs for the sheet
  const diffs = this.Sheets[sheet].diffs;
  if (diffs && diffs.length) {
    this.Editor.showProgress({ type: "top" });
 
    const method = mode ? "addCellCss" : "removeCellCss";
    const grid = this.Editor.$$("cells");
 
    // add CSS class for highlighting the cells
    diffs.forEach(d => {
      const colId = grid.columnId(d[1] + 1);
      grid[method](
        grid.getIdByIndex(d[0]),
        colId,
        "webix_docmanager_diff_excel",
        true       );
    });
 
    grid.render();     this.Editor.hideProgress();
  }
}

Related sample:  Document Manager: Working with Excel via Spreadsheet

Setting current user

The Comments module allows viewing comments for files and folders as well as sending comments on behalf of the current user.

At the same time, the Golang backend supplied for the widget does not deal with user authentication logic as each system has its own requirements for it.

So, we hardcoded the current user ID to 1 on both server and client sides. To change this, you need to take the following steps:

  • Firstly, you need to determine the current user on the server (i.e. login a new user) and specify the new value within the backend code.

  • Secondly, you should define the currentUser setting for the Comments component used in the preview/comments module:

class Comments extends docManager.views["preview/comments"] {
  config() {
    return super.config().then((ui) => {
      ui.currentUser = 2; // ID of the currently logged person
      return ui;
    });
  }
}

And override the default class with the new one for the changes to take effect:

webix.ui({
  view: "docmanager",
  url: "https://docs.webix.com/docmanager-backend/",
  override: new Map([
    [docManager.views["preview/comments"], Comments]
  ]),
});

Related sample:  Document Manager: Change Current User

Back to top