# 扩展

civet的扩展分为浏览器扩展和本地扩展两种。

# 浏览器扩展

以下示例是一个浏览器扩展。你需要先下载一个模板,以便能够方便的安装和打包扩展。

如果你对浏览器扩展开发已经很熟练了,那么可以跳过下述内容。

执行`git clone https://github.com/webbery/browser-extension-for-civet.git`命令,下载浏览器扩展模板。  
执行`npm install`命令,安装依赖项。  

接下来安装civet-extend:

npm install civet-extend@latest

环境就搭好了,非常简单。

接下来开始给扩展添加内容了。

打开模板下src/scripts目录,打开background.js,在顶部引入如下内容

import * as civet from 'civet-extend'
1

然后我们添加一个右键图片操作,将图片保存到Civet中。

let menu = {
  id: 'add-image',
  title: '添加到civet',
  contexts: ['image']
}

ext.contextMenus.create(menu)
ext.contextMenus.onClicked.addListener(
  function(info, tab) {
    switch(info.menuItemId) {
      case 'add-image':
        civet.resource.save(info.srcUrl)
        break;
      default:
        break;
    }
  }
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

其中第12行,表示将右键的图片保存到Civet中。
编写完成后,执行如下命令:

npm run build

dist目录下,将会出现chrome、firefox、opera三种浏览器的扩展。

下面可以通过浏览器扩展加载它们,进行调试了。

当然,一个完整的扩展不会如上面那般简单。例如,如果Civet没有启动,那么扩展应该将这个URL保存起来,直到Civet启动事件触发之后,同步更新。诸如此类的业务逻辑并不属于该部分内容。

一个浏览器扩展的生命周期如下:

Civet与浏览器扩展之间没有启动的先后顺序之说。
Civet是相当于一个Server,而浏览器扩展则相当于一个Client。
当浏览器扩展连接上Civet时,会将自己的唯一扩展名发送给Civet,然后接收到来自Civet的配置信息。配置内容如下所示,存放在ExtensionContext中:

{
  current: 当前资源库名称
  candidates: [
    {
      name: 资源库名,
      ext: [
        {
          name: 扩展名,
          type: UI/backgroud/browser/category
        }
      ]
    }
  ]
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

当收到这个信息时,环境的初始化已经完成。
接口:

civet.resource.load(info.srcUrl)
1

# 本地扩展

扩展安装的路径默认为安装路径下的extesions。
本地扩展需要在package.json中引入一个配置字段civet。如下所示:

{
  "name": "@civet-extend/zetora",
  "civet": {
    "activeEvents": [
      "onContntType:jpeg,jpg,tif,png",
    ]
  }
}
1
2
3
4
5
6
7
8

每个扩展包含了一个名字。
本地扩展的生命周期如下:
local-life
Civet启动时,会去extensions文件夹中,查看安装的扩展。
首先,在扩展文件夹中寻找package.json文件,检查main字段,以这个字段的值作为对应的入口文件;如果这个字段不存在,会默认index.js作为入口文件加载。
接着调用入口文件中的activate()函数,注册激活事件activeEvents,这些事件将在满足条件的时候自动触发。这个函数不是必须的

# 载入事件

onContntType标明当一个指定后缀的文件第一次被导入时将会触发read事件。同时,这个参数还表明该插件支持的文件类型。如果为空,则不会做任何判断

# 自定义界面

有时候,我们需要自定义一些界面,来展示不同内容的信息,例如论文的作者和摘要。这种情况下,就需要扩展界面功能
package.json中,onView的值支持以下几种:

Property = 1,
Navigation = 2,
Overview = 3,
ContentView = 4,
Search = 5
1
2
3
4
5

这几个值定义在了civet.d.tsViewType中,分别代表了5种类型的界面组件。例如,activeEvents中添加自定义属性面板时:

{
  "name": "@civet-extend/example",
  "civet": {
    "activeEvents": [
      "onView:Property",
    ]
  }
}
1
2
3
4
5
6
7
8

如果既需要自定义视图Overview,又需要自定义属性面板Property,可以将它们合并在一起,以逗号,分隔:

{
  "name": "@civet-extend/example",
  "civet": {
    "activeEvents": [
      "onView:Property,Overview",
    ]
  }
}
1
2
3
4
5
6
7
8

# Property模块

Property模块是展示内容属性的地方,配置如下所示,需要在activeEvents中添加onView:Property

{
  "name": "@civet-extend/example",
  "civet": {
    "activeEvents": [
      "onView:Property",
    ]
  }
}
1
2
3
4
5
6
7
8

如果想通过扩展来调整属性的展示,需要在windowonDidSelectContentItem函数中注册响应函数。这个响应函数在一个资源被选中的时候触发。
展示图片属性的代码如下所示:

import { window, ContentItemSelectedEvent, ResourceProperty } from 'civet'

function shouldDisplay(prop: ResourceProperty): boolean {
  switch(prop.name) {
    case 'filename':
    case 'color':
    case 'thumbnail':
      return false
    default:
      return true
  }
}

window.onDidSelectContentItem(async (e: ContentItemSelectedEvent) => {
  let propertyView = window.propertyView
  if (e.items.length === 1) {
    const resource = e.items[0]
    propertyView.name = resource.name
    propertyView.preview = resource.thumbnail
    window.propertyView.colorPanel.color = resource.color
    propertyView.tags = resource.tags
    propertyView.category = resource.category
    propertyView.property.splice(0, propertyView.property.length)
    for (let prop of resource.meta) {
      if (shouldDisplay(prop)) {
        propertyView.property.push(prop);
      }
    }
  }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# Overview模块

Overview模块是展示用的主界面。目前在civet中自带了两种风格的主界面,文件视图(在扩展grid_view中)和地图视图(在扩展map_view中)。
在Overview模块中,分为前端和后端。
这里的前端指的是在renderer中显示的html页面,后端是指在worker中运行的typescript程序。
在前端中,我们可能会需要跟后端交互。目前,我们提供了几种交互的方式:

  1. 命令机制
    命令机制需要开发者在package.json中,添加相关的命令。例如菜单命令:
"contributes": {
  "menus": {
    "overview/gridview": [
      {
        "command": "exportResources",
        "group": "1",
        "name": "导出文件"
      },
      ...
  }
1
2
3
4
5
6
7
8
9
10

这里定义了gridview视图的一个菜单,它的命令为exportResources,在菜单上的显示名称为导出文件
到目前为止,视图的右键菜单只能够显示菜单信息,点击时所执行的命令还没有定义。接下来需要做2件事情:a. 注入命令所需的参数;b. 定义命令在后端的响应函数。
在前端,我们提供了一个接口,供开发者注入命令的参数。其定义如下:

function injectCommandParams(command, args);
1

整个要添加的内容如下图绿色部分所示:
local-life
2. 消息机制
开发中

如下所示,通过windowcreateOverview创建一个新的主界面,gridview为这个界面的id,waterfall layout作为布局切换的展示名称。

let gridview = window.createOverview('gridview', 'waterfall layout')
1

当资源载入的时候,onResourcesLoading注册的函数会被触发:

gridview.onResourcesLoading((e: OverviewItemLoadEvent) => {
  console.info('grid view onResourcesLoading', e.resources.length)
  frame = frame.replace('{{jquery}}', jquery)
  frame = frame.replace('{{waterfall}}', waterfall)
  frame = frame.replace('{{resources}}', JSON.stringify(e.resources))
  console.info('GRID:', frame)
  gridview.html = frame
}, gridview);
1
2
3
4
5
6
7
8

在这个注册函数中,可以设置Overviewhtml内容,在界面中展示

# 添加新的搜索

如果想要添加一种新的搜索方式,就需要自定义一种搜索类型,以便搜索引擎对整个数据进行重新索引。需要详细考虑该方案的设计,待开发。

# 发布本地扩展

本地扩展以npm包的形式,托管在npm仓库中。因为civet这个域已经被使用了,所以扩展的Group使用civet-extend,其后才是扩展的名称,如:@civet-extend/example