自定义小组件中的自定义小组件

时间:2012-05-09 13:34:07

标签: javascript dojo spring-roo

不可否认,我仍然是Dojo的新手,而且我一直对Javascript很弱,所以这里有借口和邋code的代码或语言。

我正在使用Spring Roo 1.2.1RELEASE的Dojo 1.7.1。我正在从Google通过CDM加载Dojo。

我前段时间创建了一个自定义图像缩略图查看器,可以在我的网站上使用,我在Spring Roo的load-scripts.tagx中添加了一个模块给我的djConfig,它在每个页面加载时运行。缩略图Widget不遵循AMD模式,因为当时我无法使其正常工作。

这是djConfig:

  <script type="text/javascript">
    var djConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            modulePaths:    {
                "message": "${message_dojo_url}",
                "img.ArtThumbnailWidget": "${artThumbnailWidget_dojo_url}",
                "img.ArtTableWidget": "${artTableWidget_dojo_url}",
            },
        };
  </script>

以下是thumbailer的JS:

// img.ArtThumbnailWidget
dojo.provide("img.ArtThumbnailWidget");

dojo.require("dojo._base.declare");
dojo.require("dojo.parser");
dojo.require("dojo.ready");
dojo.require("dijit._WidgetBase");
dojo.require("dijit._TemplatedMixin");
dojo.require("dojox.image.LightboxNano");

// Create the widget
require([
         "dojo/_base/declare",
         "dojo/parser",
         "dojo/ready",
         "dijit/_WidgetBase",
         "dijit/_TemplatedMixin",
         "dojo/dom",
         "dojo/dom-construct",
         "dojo/on",
         "dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html",
         "dojox/image/LightboxNano",
         "dojo/domReady!"
    ], function(declare, parser, ready, _WidgetBase, _TemplatedMixin, dom, domConstruct, on, template) {

    dojo.declare("img.ArtThumbnailWidget",[dijit._WidgetBase, dijit._TemplatedMixin], {
        /* Our properties will go here */

        // Art JSON object, default is null
        art: null,

        // Viewer ID (the username of the person looking at this image), which will default to null
        viewerId: null,

        // maxThumbnailSize is how large of an image to return for the thumbnail.  The back-end will resize the thumbnail accordingly
        maxThumbnailSize: 100,

        // maxImageSize is how large of an image to return for the LightboxNano.  The back-end will resize the image accordingly
        maxImageSize: 500,

        // Our template - important!
        templateString: template,

        // A class to be applied to the root node in our template
        baseClass: "artThumbnailWidget",

        // Specifies there are widgets in the template itself that need to be rendered as well
        widgetsInTemplate: true,

        // Competition-related vars
        competitionUrlBase: null,
        competitionButtonIconUrl: null,

        /* This is called once the DOM structure is ready, but before anything is shown */
        postCreate: function() {
            // Get a DOM node reference for the root of our widget
            var domNode = this.domNode;

            // Run any parent postCreate processes - can be done at any point
            this.inherited(arguments);

            if(this.art!=null && this.viewerId!=null && this.art.owner.name == this.viewerId) {     // If the view is the owner, add the toolbar
                // TODO: We need to clean this up, make it "prettier", and make the URLs more generic
                var toolbarNode = domConstruct.create("div", {}, this.containerNode);

                if(this.competitionUrlBase!=null) {
                    var url = this.competitionUrlBase;
                    if(url.indexOf('?')<0) {    // URL does not have a '?'
                        url = url+"?";
                    } else {    // URL has a '?', so we need to tack on and additional '&'
                        url = url+"&";
                    }
                    url = url+"username="+this.art.owner.name+"&artPieceId="+this.art.id;

                    var compButtonNode = domConstruct.create("a",
                            {
                                href: url,
                            },toolbarNode);
                    var compButtonImg = domConstruct.create("img",
                            {
                                src: this.competitionButtonIconUrl,
                                width: this.maxThumbnailSize/4,
                                height: this.maxThumbnailSize/4,
                            },compButtonNode);
                }
            }
        },

        /* This private method is used to re-set the node values when something changes  */
        _resetNodeValues: function() {
            if(this.art !=null) {
                // Using our thumbnailNode attach point, set its src value
                this.thumbnailNode.src = this.art.url+"?maxSize="+this.maxThumbnailSize;
                this.thumbnailNode.alt = this.art.title;
                this.thumbnailNode.width = this.maxThumbnailSize;
                this.thumbnailNode.height = this.maxThumbnailSize;

                // Now setup the link for the LightboxNano
                var lightboxNano = new dojox.image.LightboxNano({
                    href: this.art.url+"?maxSize="+this.maxImageSize,
                },this.thumbnailNode);
            }
        },

        /* This is called anytime the "art" attribute is set.  Consider is a "setter" method */
        _setArtAttr: function(av) {
            if (av != null) {
                // Save it on our widget instance - note that
                // we're using _set, to support anyone using
                // our widget's Watch functionality, to watch values change
                this._set("art", av);

                this._resetNodeValues();
            } else {
                // We could have a default here...would be an error, since we
                // shouldn't be calling this without an art object
            }
        },

        _setMaxThumbnailSizeAttr: function(ms) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("maxThumbnailSize", ms);

            this._resetNodeValues();
        },

        _setMaxImageSizeAttr: function(ms) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("maxImageSize",ms);

            this._resetNodeValues();
        }
    });     // End of the widget

});

现在我正在尝试添加另一个自定义组件,即上述缩略图的表格。新代码需要引用这个旧的Widget,但我似乎无法让它工作。

新的表格小部件(到目前为止):

// in "img/ArtTableWidget"
define([
        "dojo/_base/declare", "dojo/parser", 
        "dijit/_WidgetBase", "dijit/_TemplatedMixin", 
        "dojo/dom", "dojo/dom-construct","img/ArtThumbnailWidget",
        "dojo/text!./ArtTableWidget/templates/ArtTableWidget.html"], 
    function(declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
        return declare("img.ArtTableWidget",[dijit._WidgetBase,dijit._TemplatedMixin], {
            // Default values for the ArtTable

            // The base URL to use for downloading the photos
            artUrlBase: null,

            // The base URL used for submitting competitions and the button URL
            newCompetitionUrlBase: null,
            newCompetitionButtonIconUrl: null,

            // Indicates what params on the URL are used to control page 
            // and size.  These will be appended to the URL as needed.
            pageNumberParameterName: "page",
            pageSizeNumberParameterName: "size",

            // Holds the page and size
            page: 1,
            size: 15,
            totalPages: 0,

            columns: 3,

            // Holds the current list of "art"
            artList: [],

            // The userid currently viewing
            viewerId: null,

            // Our HTML template
            templateString: template,

            baseClass: "artTableWidget",

            // Specifies there are widgets in the template itself that need to be rendered as well
            widgetsInTemplate: true,

            // Functions //

            postCreate: function() {
                this._load(this.page);
            },

            // Loads the given page
            _load: function(pageToLoad) {
                if(pageToLoad==null) {
                    pageToLoad=1;
                }

                // Generate the URL
                genUrl = this.artUrlBase.indexOf("?")>=0 ? this.artUrlBase+"&page="+pageToLoad+"&size="+this.size : this.artUrlBase+"?page="+pageToLoad+"&size="+this.size;

                // Make the call to the backend
                dojo.xhrGet({
                    url: genUrl,
                    handleAs: "json",
                    tableWidget: this,
                    load: function(data,ioArgs) {
                        this.tableWidget.page = data.page;
                        this.tableWidget.totalPages = data.totalPages;
                        this.tableWidget.artList = data.data;

                        this.tableWidget._updateTable();
                    }
                });
            },

            _updateTable: function() {
                // Fix the buttons at the bottom

                // Clear the artTable
                domConstruct.empty(this.artTable);

                // Loop through the art and build the rows
                tableRow = tableRow = domConstruct.create("tr",{},this.artTable);
                dojo.forEach(this.artList,function(art,index) {
                    if(index % columns == 0) {
                        tableRow = domConstruct.create("tr",{},this.artTable);
                    }
                    tableColumn = domConstruct.create("td",{style: { marginLeft: "auto", marginRight: "auto" }},tableRow);
                    var tnNode = new ArtThumbnailWidget({
                        art: art,
                        viewerId: this.viewerId,
                        competitionUrlBase: this.newCompetitionUrlBase,
                        competitionButtonIconUrl: this.newCompetitionButtonIconUrl,
                    });
                    tnNode.placeAt(tableColumn);
                });
            }
        });
});

然而,当我在Chrome中运行新组件时,我在dojo.js.uncompressed.js第1716行中得到一般错误。错误的消息是“multipleDefine”,附加的Object看起来是我的ArtTableWidget。我注意到在挖掘这个对象时,“deps”成员看起来是顶部define()中定义的所有依赖项的数组,其中包含img / ArtThumbnailWidget,但是“pack”成员未定义。我猜它只是没有加载我的模块或其他东西。

错误(对不起,如果复制/粘贴看起来不正确)是:

dojo.js.uncompressed.js:1716
Error
  arguments: undefined
  get stack: function getter() { [native code] }
  info: Object
  cacheId: 0
  cjs: Object
  def: function (declare,parser,_WidgetBase,_TemplatedMixin, dom, domConstruct, ArtThumbnailWidget, template) {
  deps: Array[8]
    0: Object
    1: Object
    2: Object
    3: Object
    4: Object
    5: Object
    6: Object
      cacheId: 0
      def: 0
      executed: 4
      injected: 2
      isAmd: false
      isXd: null
      mid: "img/ArtThumbnailWidget"
      pack: undefined
      pid: ""
      result: Object
      url: "/ArtSite/resources/img/ArtThumbnailWidget.js"
      __proto__: Object
    7: Object
    length: 8
    __proto__: Array[0]
    executed: 0
    injected: 2
    isAmd: false
    isXd: null
    mid: "img/ArtTableWidget"
    node: HTMLScriptElement
    pack: undefined
    pid: ""
    require: function (a1, a2, a3){
    result: Object
    url: "/ArtSite/resources/img/ArtTableWidget.js"
    __proto__: Object
  message: "multipleDefine"
  set stack: function setter() { [native code] }
  src: "dojoLoader"
  type: undefined
  __proto__: ErrorPrototype
  dojo.js.uncompressed.js:1719src: dojoLoader
  dojo.js.uncompressed.js:1719info: 
  Object
  dojo.js.uncompressed.js:1721.

我需要一些帮助才能回到正确的轨道。

编辑1 我使用BuffaloBuffalo的回复中的信息更新了所有模块,除了dojoConfig中的“路径”,我使用了以下内容:

    <script type="text/javascript">
    var djConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            packages: [
                 { name: "message", location: "${message_dojo_module_base_url}" },
                 { name: "img", location: "${img_dojo_module_base_url}" }
            ]
        };
  </script>

似乎找到了.js文件,但没有找到使用 dojo / text 加载的模板。我试过做“./path/Template.html”和“/module/path/Template.html”,但是第一个尝试通过CDN(上面链接的Google API站点)尝试解析URL,后者似乎想要一条完全合格的道路。我快门进入一条完整的路径,因为这似乎是一种肮脏的方式。我也试过添加dojoConfig的路径:

        paths: [
             { "message" : "${message_dojo_module_base_url}" }
        ]

但这似乎没有任何帮助,导致Chrome的JS控制台出现一些非常糟糕的错误。

如果我正确阅读here,那么dojo / text不会使用这些模块吗?

2 个答案:

答案 0 :(得分:1)

很难说出确切的问题是什么,但有几件事情突然发生在我身上:

如果使用1.7,djConfig对象应命名为dojoConfig(dojoConfig仍可正常工作,但也可以更新它。)

modulePaths属性应更新为path。如果img.ArtThumbnailWidgetimg.ArtTableWidget位于公共目录中,您可以使用以下内容:

var dojoConfig = {
            parseOnLoad: false, 
            isDebug: false, 
            locale: '${fn:toLowerCase(userLocale)}',
            paths:    {
                "message": "${message_dojo_url}",
                "img": "${art_module_url}"
            }
        };

第二件事是img.ArtThumbnailWidget中的混合遗留/ amd加载器样式。你有99%的AMD风格。您需要做的就是

  1. 删除dojo.provide和dojo.requires
  2. require([],function(){..});更新为define([],function(){..});
  3. 更新声明中的引用以使用局部变量而不是全局变量:

    //ArtThumbnailWidget
    define('img/ArtThumbnailWidget', [
        "dojo/_base/declare",
        "dojo/parser",
        "dojo/ready",
        "dijit/_WidgetBase",
        "dijit/_TemplatedMixin",
        "dojo/dom",
        "dojo/dom-construct",
        "dojo/on",
        "dojo/text!img/ArtThumbnailWidget/templates/ArtThumbnailWidget.html",
        "dojox/image/LightboxNano",
        "dojo/domReady!"
        ], function (declare, parser, ready, _WidgetBase, _TemplatedMixin, dom, domConstruct, on, template) {
    
      return declare("img.ArtThumbnailWidget", [_WidgetBase, _TemplatedMixin], {
        /* Our properties will go here */
    
        // Art JSON object, default is null
        art: null,
    
        // Viewer ID (the username of the person looking at this image), which will default to null
        viewerId: null,
    
        // maxThumbnailSize is how large of an image to return for the thumbnail.  The back-end will resize the thumbnail accordingly
        maxThumbnailSize: 100,
    
        // maxImageSize is how large of an image to return for the LightboxNano.  The back-end will resize the image accordingly
        maxImageSize: 500,
    
        // Our template - important!
        templateString: template,
    
        // A class to be applied to the root node in our template
        baseClass: "artThumbnailWidget",
    
        // Specifies there are widgets in the template itself that need to be rendered as well
        widgetsInTemplate: true,
    
        // Competition-related vars
        competitionUrlBase: null,
        competitionButtonIconUrl: null,
    
        /* This is called once the DOM structure is ready, but before anything is shown */
        postCreate: function () {
          // Get a DOM node reference for the root of our widget
          var domNode = this.domNode;
    
          // Run any parent postCreate processes - can be done at any point
          this.inherited(arguments);
    
          if (this.art != null && this.viewerId != null && this.art.owner.name == this.viewerId) { // If the view is the owner, add the toolbar
            // TODO: We need to clean this up, make it "prettier", and make the URLs more generic
            var toolbarNode = domConstruct.create("div", {}, this.containerNode);
    
            if (this.competitionUrlBase != null) {
              var url = this.competitionUrlBase;
              if (url.indexOf('?') < 0) { // URL does not have a '?'
                url = url + "?";
              } else { // URL has a '?', so we need to tack on and additional '&'
                url = url + "&";
              }
              url = url + "username=" + this.art.owner.name + "&artPieceId=" + this.art.id;
    
              var compButtonNode = domConstruct.create("a", {
                href: url,
              }, toolbarNode);
              var compButtonImg = domConstruct.create("img", {
                src: this.competitionButtonIconUrl,
                width: this.maxThumbnailSize / 4,
                height: this.maxThumbnailSize / 4,
              }, compButtonNode);
            }
          }
        },
    
        /* This private method is used to re-set the node values when something changes  */
        _resetNodeValues: function () {
          if (this.art != null) {
            // Using our thumbnailNode attach point, set its src value
            this.thumbnailNode.src = this.art.url + "?maxSize=" + this.maxThumbnailSize;
            this.thumbnailNode.alt = this.art.title;
            this.thumbnailNode.width = this.maxThumbnailSize;
            this.thumbnailNode.height = this.maxThumbnailSize;
    
            // Now setup the link for the LightboxNano
            var lightboxNano = new LightboxNano({
              href: this.art.url + "?maxSize=" + this.maxImageSize,
            }, this.thumbnailNode);
          }
        },
    
        /* This is called anytime the "art" attribute is set.  Consider is a "setter" method */
        _setArtAttr: function (av) {
          if (av != null) {
            // Save it on our widget instance - note that
            // we're using _set, to support anyone using
            // our widget's Watch functionality, to watch values change
            this._set("art", av);
    
            this._resetNodeValues();
          } else {
            // We could have a default here...would be an error, since we
            // shouldn't be calling this without an art object
          }
        },
    
        _setMaxThumbnailSizeAttr: function (ms) {
          // Save it on our widget instance - note that
          // we're using _set, to support anyone using
          // our widget's Watch functionality, to watch values change
          this._set("maxThumbnailSize", ms);
    
          this._resetNodeValues();
        },
    
        _setMaxImageSizeAttr: function (ms) {
          // Save it on our widget instance - note that
          // we're using _set, to support anyone using
          // our widget's Watch functionality, to watch values change
          this._set("maxImageSize", ms);
    
          this._resetNodeValues();
        }
      }); // End of the widget
    });
    
  4. 我怀疑ArtThumbnailWidget中遗留风格与amd风格的结合让人感到困惑ArtTableWidget

答案 1 :(得分:0)

所以,是的,这里有很多可能有问题的东西。你能得到一个更小的例子吗?

  1. 肯定值得查看浏览器开发人员工具的“网络”标签,以查看正在尝试加载的内容。这通常有助于模块解析。同步运行(我认为你是),而不是异步模式也有助于诊断。
  2. 您是否应该在modulePaths中注册img / ArtThumbnailWidget而不是img.ArtThumbnailWidget?
  3. 从长远来看,您可能希望注册包而不是逐个模块...
  4. 你应该能够在你的小部件中引用dojo / text!./ templates / ArtThumbnailWidget.html而不是dojo / text!img / ArtThumbnailWidget / templates / ArtThumbnailWidget.html,但这只会在你发现后变得相关我得到了小部件加载。 (模块的要求是相对于模块处理的。)