使用第三方 npm jquery 模块的自定义小部件

Custom widget using third party npm jquery module

在对文档进行更多研究后,自定义小部件似乎是尝试实现我需要的最佳方式:自动完成下拉列表可在用户键入时按标题加载 article/blog 个帖子 (我选择了 npm jquery-autocomplete、https://www.npmjs.com/package/jquery-autocomplete,因为我认为这个功能很容易实现,但也许 apos 本身有更简单的方法)。

我按照小部件教程中的说明进行操作,http://apostrophecms.org/docs/tutorials/getting-started/custom-widgets.html,我认为我几乎已经连接好了,但我没有看到呈现的搜索小部件(视图),而是 dom 显示一个空元素 div class="apos-area" data-apos-area="" 元素,这表明将所有部分链接在一起之间缺少一块,但我可以'根据文档示例代码找出缺失的部分。

这是问题 #1,下面的代码中缺少什么来阻止 search.html 视图加载?

app.js

 modules: {
    'search-widget': {}
 }

lib\modules\search-widget\index.js

module.exports = {
  extend: 'apostrophe-widgets',
  label: 'SiteSearch',
  addFields: [{
        type: 'string',
        name: 'title',
        label: 'Title'
    },
    {
        type: 'string',
        name: 'url',
        label: 'Url'
    }
  ],
  construct: function(self, options) {

    //load third party styles and scripts?
    var superPushAssets = self.pushAssets;
       self.pushAssets = function() {
       superPushAssets();
       self.pushAsset('stylesheet', 'autocomplete', { when: 'always' });
       self.pushAsset('script', 'autocomplete', { when: 'always' })
     };

    //get the data
    self.pageBeforeSend = function(req, callback) {

        var criteria = [
            { "type": "apostrophe-blog" },
            { "published": true }
        ];
        criteria = { $and: criteria };

        self.apos.docs.find(req, criteria).sort({ title: 1 }).toArray(function(err, autocomplete) {
            if (err) {
                return callback(err);
            }
            //Can I do something like this to load the widget data?
            req.data.autocomplete = autocomplete;

            return callback(null);

        });
    }
}
};

lib\modules\search-widget\views\search.html

<div id="custom-search-input">
    <div class="input-group col-md-12">
        <input type="text" class="form-control input-lg" id="site-search" placeholder="Search" />
        <span class="input-group-btn">
            <button class="btn btn-info btn-lg" type="button">
                <i class="glyphicon glyphicon-search"></i>
            </button>
       </span>
    </div>
</div>

lib\modules\apostrophe-pages\views\pages\home.html

  {% extends 'apostrophe-templates:layout.html' %} {% block bodyClass %}{{ super() }} home-page{% endblock %} {% block title %}Help Site: {{ data.page.title | e }}{% endblock %} {% block main %}
    <section id="promo" class="promo section offset-header">
        <div class="container text-center">
            <div class="row">
                <div class="col-md-offset-2 col-md-8 col-sm-6 col-xs-12">
                    <!--search widget-->
                    {{ apos.singleton(data.page, 'search', 'search-widget') }}
                </div>
            </div>
        </div>
    </section>

问题 #2 是,在 search-widget\index.js 构造函数中,这是加载渲染到 dom 并使用它所需的第三方资产的正确方法吗?

问题 #3 是,在 search.html 中,我可以简单地使用 data.page 将数据发送到 jquery-autocomplete object 吗?

<div id="custom-search-input">
    <div class="input-group col-md-12">
        <input type="text" class="form-control input-lg" id="site-search" placeholder="Search" />
        <span class="input-group-btn">
            <button class="btn btn-info btn-lg" type="button">
                <i class="glyphicon glyphicon-search"></i>
        </button>
    </span>
    </div>
</div>
<script>  
 $(function() {
    $("#site-search").autocomplete({
            source: {{ data.autocomplete | json }}
        }); 
  });
</script>

如你所知,我是 P'unk Avenue 的 Apostrophe 团队的负责人。

首先,提供小部件的模块的名称应该以“-widgets”结尾,而不是“-widget”。它必须是复数(MAP - Modules Are Plural)。这是因为将有一个模块实例来管理小部件的所有服务器端需求(这被称为 "singleton pattern")。它不是 "one widget," 它是一个管理所有此类小部件的模块。

其次,像现在一样向 pageBeforeSend 添加代码将 运行 它始终 — 无论此页面是否包含小部件.从长远来看,这对于性能来说并不是最佳的。特别是因为您正在加载网站上的所有博客 post。事情会很快变慢。

我强烈建议您查看 apostrophe-twitter-widgets 模块及其源代码。除其他外,该模块实现了一个服务器端 Express 路由,专门为小部件提供数据,何时以及是否在页面上实际存在小部件实例并且它想知道。它实现了一个 "widget player," 方法,当页面上有这种小部件时,该方法会在浏览器端调用。

该模块还包含一些自定义浏览器端资产并正确推送它们,这也将回答我在这个问题的表面之下看到的一些问题。

但是,请注意,Apostrophe 已经总是将 jquery 自动完成推送到浏览器。这恰好是我们用于连接和标记的自动完成实现。因此,您无需担心推动该资产。

您的服务器端路由应该调用 autocomplete 游标过滤器,而不是一直获取世界上的一切。 (: Apostrophe 经常使用自动完成功能,因此它已经提供了一种方便的方式,可以以一种智能且实现良好的方式获取与前缀匹配的内容。

如果您不清楚游标过滤器,请务必阅读有关使用模型层的 HOWTO。

此外,始终使用适当模块的 find 方法,不要重新发明它并尝试自己弄清楚是什么让博客 post 适合 return。

您的路线可能如下所示:

// Inside the construct function of your module...

self.route('get', 'autocomplete', function(req, res) {
  return self.apos.docs.getManager('apostrophe-blog')
    .find()
    .autocomplete(req.query.term)
    .limit(10)
    .projection({
      areas: false,
      joins: false
    })
    .toArray(function(err, posts) {
      if (err) {
        res.statusCode = 500;
        return res.send('error');
      }
      return res.send(_.map(posts, function(post) {
        return {
          value: post._url,
          label: post.title
        }
      }));
    }
  );
});

那将进入模块的 construct 函数。

现在 /modules/search-widgets/autocomplete 有一条 GET 方法 Express 路线等待您的来信。通过在浏览器端编写一个播放器方法来完成这项工作。您可以在 apostrophe-twitter-widgets 代码中看到它们的外观以及将它们放在何处。当然,您的窗口小部件模板中的文本输入字段会调用 .autocomplete()。它将 jquery 自动完成 source 选项设置为 /modules/search-widgets/autocomplete

希望对您有所帮助!