【山大智云项目日志】(八)源码分析之seahub-frontend-components-toolbar

2021SC@SDUSC
这一次的博客聚焦toolbar,也就是工具条。在以后的开发中可能会涉及到增加toolbar的功能,因此对toolbar组件的源码分析,以及这些UI界面对应的代码在项目的哪些文件中,这次需要搞清楚。
首先看最上边的bar:

如图:在这里插入图片描述

let searchPlaceholder = this.props.searchPlaceholder || gettext('Search Files'); //预置搜索内容
    return (
<div className="common-toolbar">
        {isPro && (
          <Search //搜索框
            repoID={this.props.repoID} //仓库ID,用户在对应资料库下的搜索
            placeholder={searchPlaceholder} //搜索内容
            onSearchedClick={this.props.onSearchedClick} //事件函数
          />
        )}
        {this.props.isLibView && !isPro &&
          <SearchByName                
            repoID={this.props.repoID}
            repoName={this.props.repoName}
          />
        }
        <Notification />  //通知组件
        <Account />          //用户组件
        {showLogoutIcon && (<Logout />)} //功能图标
      </div>

咱们上上此已经对Notification组件和Account组件进行过分析了,详情请见源码分析之seahub-frontend-components-Account。
这里简单看一下搜索组件:
在common-toolbar中,search作为子组件,接受了common-toolbar传过来的三个参数,分别是repo_ID,搜索内容,以及事件函数。在子组件search中,这三个参数的作用:
repo_ID确定要搜索的库:

 onShowMore = () => {
    let repoID = this.props.repoID;
    let newValue = this.state.value;
    let queryData = {
      q: newValue,
      search_repo: repoID ? repoID : 'all',
      search_ftypes: 'all',
    };
    let params = '';
    for (let key in queryData) {
      params += key + '=' + queryData[key] + '&';
    }

    window.location = siteRoot + 'search/?' + params.slice(0, params.length - 1);
  }

Placeholder作为搜索的关键词,在search组件的input框中发挥作用。

 <input
                  type="text"
                  className="form-control search-input"
                  name="query"
                  placeholder={this.props.placeholder}
                  style={style}
                  value={this.state.value}
                  onFocus={this.onFocusHandler}
                  onChange={this.onChangeHandler}
                  autoComplete="off"
                />
                {(this.state.isCloseShow && username) &&
                  <i className='search-icon-right input-icon-addon fas fa-external-link-alt search-icon-arrow'
                    onClick={this.onSearchPage}></i> 
                }

通过点击最后的icon,调用API的SearchPage函数,实现搜索。查找结果被封装成了Search-result组件。包括每一个文件的文件名,资料库名,文件链接,以及是否危险的标识。

<li className="search-result-item" onClick={this.onClickHandler}>
        <img className={className} src={fileIconUrl} alt="" />
        <div className="item-content">
          <div className="item-name ellipsis">{item.name}</div>
          <div className="item-link ellipsis">{item.repo_name}/{item.link_content}</div>
          <div className="item-text ellipsis" dangerouslySetInnerHTML={{__html: item.content}}></div>
        </div>
      </li>

搜索的方式以及涉及到的算法都在服务端,这里先对前端的一些组件的实现以及位置做一下分析。后边分析后端的时候会留意搜索算法的。

下面看operation-toolbar,这一部分对应的是进入每个库时,最上面一行的操作栏,如图:
在这里插入图片描述
这一部分对应了两种显示方式,每一种对应的事件函数不同。区分普通操作栏还是下拉操作栏的条件是:是否是客户端Utils.isDesktop()
在这里插入图片描述
group-toolbar
先看UI界面图:
在这里插入图片描述
看下面代码,除了基本的按钮,和icon图标以及对应的点击事件,我们还看到有一个span,用来决定是否显示侧边面板,疑惑的是这里并没有发现类似功能。然后就是最后看到了我们上面分析过的CommonToolbar,也就是搜索框。这一部分封装成群组工具栏,然后渲染到页面的指定位置。

return (
      <div className="main-panel-north border-left-show">
        <div className="cur-view-toolbar">
          <span title="Side Nav Menu" onClick={onShowSidePanel} className="sf2-icon-menu side-nav-toggle hidden-md-up d-md-none"></span>
          {canAddGroup && (
            <div className="operation">
              <MediaQuery query="(min-width: 768px)">
                <Button color="btn btn-secondary operation-item" onClick={this.props.toggleAddGroupModal}>
                  <i className="fas fa-plus-square text-secondary mr-1"></i>{gettext('New Group')}
                </Button>
              </MediaQuery>
              <MediaQuery query="(max-width: 767.8px)">
                <span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('New Group')} onClick={this.props.toggleAddGroupModal}></span>
              </MediaQuery>
            </div>
          )}
        </div>
        <CommonToolbar searchPlaceholder={this.props.searchPlaceholder} onSearchedClick={onSearchedClick}/>
      </div>
    );

invitation-toolbar
这是一个负责邀请用户进入group的工具组件。同样系统先判断是否是desktop,然后决定页面样式:
同样的,最下面仍有搜索框,并一起封装到指定工具栏处。

{Utils.isDesktop() ? (
            <div className="operation">
              <Button color="btn btn-secondary operation-item" onClick={toggleInvitePeopleDialog}>
                <i className="fas fa-plus-square text-secondary mr-1"></i>{gettext('Invite Guest')}
              </Button>
            </div>
          ) : (
            <span className="sf2-icon-plus mobile-toolbar-icon" title={gettext('Invite Guest')} onClick={toggleInvitePeopleDialog}></span>
          )}
        </div>
        <CommonToolbar searchPlaceholder={this.props.searchPlaceholder} onSearchedClick={onSearchedClick}/>
      </div>
    );

下面是markdown-view-toolbar:这一部分没有分析的必要,因为海思的人太厉害了,将这一出写的让人五体投地,这就是标准的markdown编辑器了,如图:
在这里插入图片描述
这种实现的网页版的编辑器功能十分强大,基本上涵盖了文本编辑的大部分功能,还还以切换成普通版的类似于CSDN博客的编辑界面。
在这里插入图片描述
详细源码见github-markdown-view-toolbar

组件multiple-dir-operation-toolbar,主要是用户在文件未打开时的操作工具栏,可以实现文件的移动、复制、下载、删除等功能。
先锁定这部分内容对应的界面如图:
在这里插入图片描述
这部分的工具栏显示,必须要选中文件才会出现,代码实现如下:

(userPerm === 'rw' || userPerm === 'admin' || isCustomPermission)

也就是在用户有选中事件之后才会有该工具栏。
同时点击每个操作按钮会有相应的Dialog,这个在上次分析中有设计,由于dialog种类较多,以及大多数实现都极为相似,目的是为了避免不必要的url跳转。
代码截图如下:
在这里插入图片描述
在这里插入图片描述
repo-view-bar组件
对应于在资料库时,不管是在私人资料库还是在共享资料库,对应于最上面的操作工具栏。
UI界面如图:
在这里插入图片描述
这部分代码也比较简单
在这里插入图片描述
就是点击NewLibrary按钮后,会出现新建资料库的Dialog,点击More会以下拉菜单栏的方式出现删除资料库的按钮,点击删除按钮同样是触发一个Dialog。然后具体在Dialog中调用对应的接口实现库的增删。
view-mode-toolbar
对应于文件的三种查看模式:列表,方格,列。
在这里插入图片描述
这里是切换模式调用的函数,至于具体的switchViewMode是在view-mode-toolbar的父组件LibContentView.js中实现的。

switchViewMode = (e) => {
    e.preventDefault();
    let id = e.target.id;
    if (id === this.props.currentMode) {
      return;
    }
    this.props.switchViewMode(id);
  }

//LibContentView中的实现。
  switchViewMode = (mode) => {
    if (mode === this.state.currentMode) {
      return;
    }
    if (mode === 'detail') {
      this.toggleDirentDetail();
      return;
    }
    cookie.save('seafile_view_mode', mode);
    let path = this.state.path;
    if (this.state.currentMode === 'column' && this.state.isViewFile) {
      path = Utils.getDirName(path);
      this.setState({
        path: path,
        isViewFile: false,
      });
      let repoInfo = this.state.currentRepoInfo;

      let url = siteRoot + 'library/' + repoInfo.repo_id + '/' + encodeURIComponent(repoInfo.repo_name) + Utils.encodePath(path);
      window.history.pushState({url: url, path: path}, path, url);
    }

    if (mode === 'column') {
      this.loadSidePanel(this.state.path);
    }
    this.isNeedUpdateHistoryState = false;
    this.setState({currentMode: mode});
    this.showDir(path);
  }

列表布局:
在这里插入图片描述
方格布局:
在这里插入图片描述列布局:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值