Plone核心包:plone.app.content解读
Plone核心包:plone.app.content解读
http://www.315ok.org/blogfolder/57906
http://www.315ok.org/logo.png
Plone核心包:plone.app.content解读
Plone核心包:plone.app.content解读
plone.app.content 包含了各种Plone的内置核心视图,如folder_contents、plonejsi18n、getVocabulary等等。包结构如下:
路径:plone.app.content
最重要的文件是setup.py,这里定义了包结构,包的依存部件,测试依存件等。
路径:plone.app.content/plone/app/content
这里testing.py定义测试环境,interfaces.py定义了event、Adapter等接口。
路径:plone.app.content/plone/app/content/browser
路径:plone.app.content/plone/app/content/browser/content
folder_content视图定义在这里的configure.zcml中。
主要视图定义在browser/configure.zcml和browser/content/configure.zcml两处,看下述代码:
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:five="http://namespaces.zope.org/five">
<!-- Adding view -->
<browser:view
for="Products.CMFCore.interfaces.IFolderish"
name="+"
class=".adding.CMFAdding"
permission="cmf.AddPortalContent"
/>
<!-- Folder contents -->
<include package=".contents" />
<!-- Review list -->
<browser:page
for="*"
class=".reviewlist.FullReviewListView"
name="full_review_list"
template="full_review_list.pt"
permission="cmf.ReviewPortalContent" />
<browser:page
for="*"
class=".reviewlist.ReviewListBrowserView"
attribute="update_table"
name="reviewlist_get_table"
permission="cmf.ReviewPortalContent" />
<!-- Content status history -->
<browser:page
for="*"
name="content_status_history"
class=".content_status_history.ContentStatusHistoryView"
permission="cmf.ModifyPortalContent"
/>
<!-- Folder factories -->
<browser:page
for="*"
name="folder_factories"
class=".folderfactories.FolderFactoriesView"
template="folderfactories.pt"
permission="cmf.AddPortalContent"
/>
<!-- Constrain container allowed content types -->
<permission
id="plone.ModifyConstrainTypes"
title="Modify constrain types"
/>
<browser:page
name="folder_constraintypes_form"
for="Products.CMFCore.interfaces.IFolderish"
permission="plone.ModifyConstrainTypes"
class=".constraintypes.ConstrainsFormView"
/>
<utility
component=".constraintypes.ValidTypesFactory"
name="plone.app.content.ValidAddableTypes"
/>
<!-- Required for cmf.ModifyViewTemplate -->
<include package="Products.CMFDynamicViewFTI" />
<!-- Select default view -->
<browser:page
for="*"
name="select_default_view"
class=".selection.DefaultViewSelectionView"
template="templates/select_default_view.pt"
permission="cmf.ModifyViewTemplate"
/>
<browser:page
for="*"
name="selectViewTemplate"
class=".selection.DefaultViewSelectionView"
attribute="selectViewTemplate"
permission="cmf.ModifyViewTemplate"
/>
<!-- Select default page view -->
<browser:page
for="*"
name="select_default_page"
class=".selection.DefaultPageSelectionView"
template="templates/select_default_page.pt"
permission="cmf.ModifyViewTemplate"
/>
<!-- Actions -->
<browser:page
for="*"
name="delete_confirmation"
class=".actions.DeleteConfirmationForm"
permission="zope2.DeleteObjects"
/>
<browser:page
for="*"
name="folder_rename"
class=".actions.RenameForm"
permission="cmf.ModifyPortalContent"
/>
<browser:page
for="*"
name="object_rename"
class=".actions.RenameForm"
permission="cmf.ModifyPortalContent"
/>
<adapter factory=".actions.default_new_id" name="default" />
<adapter factory=".actions.default_new_title" name="default" />
<browser:page
for="*"
name="object_cut"
class=".actions.ObjectCutView"
permission="zope2.DeleteObjects"
/>
<browser:page
for="*"
name="object_copy"
class=".actions.ObjectCopyView"
permission="zope2.CopyOrMove"
/>
<browser:page
for="*"
name="object_paste"
class=".actions.ObjectPasteView"
permission="cmf.AddPortalContent"
/>
<browser:page
for="*"
name="object_delete"
class=".actions.ObjectDeleteView"
permission="zope2.DeleteObjects"
/>
<browser:page
name="getVocabulary"
for="*"
class=".vocabulary.VocabularyView"
permission="zope2.View"
/>
<browser:page
name="getSource"
for="z3c.form.interfaces.IWidget"
class=".vocabulary.SourceView"
permission="zope.Public"
/>
<browser:page
name="fileUpload"
for="Products.CMFCore.interfaces._content.IFolderish"
class=".file.FileUploadView"
permission="zope2.View"
/>
<browser:page
name="qsOptions"
for="plone.app.layout.navigation.interfaces.INavigationRoot"
class=".query.QueryStringIndexOptions"
permission="zope2.View"
/>
<browser:view
for="plone.app.layout.navigation.interfaces.INavigationRoot"
name="plonejsi18n"
class=".i18n.i18njs"
permission="zope2.View"
/>
<browser:page
for="*"
name="allow_upload"
class=".file.AllowUploadView"
permission="cmf.AddPortalContent"
/>
</configure>
上述文件路径为:plone.app.content/plone/app/content/browser/configure.zcml
<configure
xmlns="http://namespaces.zope.org/zope"
xmlns:browser="http://namespaces.zope.org/browser"
xmlns:plone="http://namespaces.plone.org/plone"
xmlns:i18n="http://namespaces.zope.org/i18n">
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
class=".FolderContentsView"
name="folder_contents"
template="templates/folder_contents.pt"
permission="cmf.ListFolderContents"
/>
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-contextInfo"
class=".ContextInfo"
permission="cmf.ListFolderContents"
/>
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-setDefaultPage"
class=".defaultpage.SetDefaultPageActionView"
permission="cmf.ModifyPortalContent"
/>
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-itemOrder"
class=".rearrange.ItemOrderActionView"
permission="cmf.ModifyPortalContent"
/>
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-rearrange"
class=".rearrange.RearrangeActionView"
permission="cmf.ModifyPortalContent"
/>
<!-- buttons -->
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-rename"
class=".rename.RenameActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".rename.RenameAction"
provides="plone.app.content.interfaces.IStructureAction"
name="rename" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-tags"
class=".tags.TagsActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".tags.TagsAction"
provides="plone.app.content.interfaces.IStructureAction"
name="tags" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-delete"
class=".delete.DeleteActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".delete.DeleteAction"
provides="plone.app.content.interfaces.IStructureAction"
name="delete" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-workflow"
class=".workflow.WorkflowActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".workflow.WorkflowAction"
provides="plone.app.content.interfaces.IStructureAction"
name="workflow" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-properties"
class=".properties.PropertiesActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".properties.PropertiesAction"
provides="plone.app.content.interfaces.IStructureAction"
name="properties" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-copy"
class=".copy.CopyActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".copy.CopyAction"
provides="plone.app.content.interfaces.IStructureAction"
name="copy" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-cut"
class=".cut.CutActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".cut.CutAction"
provides="plone.app.content.interfaces.IStructureAction"
name="cut" />
<browser:page
for="Products.CMFCore.interfaces._content.IFolderish"
name="fc-paste"
class=".paste.PasteActionView"
permission="cmf.ListFolderContents"
/>
<utility component=".paste.PasteAction"
provides="plone.app.content.interfaces.IStructureAction"
name="paste" />
</configure>
上述文件路径为:plone.app.content/plone/app/content/browser/contents/configure.zcml
本文以folder_contents视图为例,解释设计思路和实现方式:folder_contents视图是一个较为复杂的视图,设计思想:
- 视图页面通过templates/folder_contents.pt文件给出呈现入口点
<metal:content-core fill-slot="content-core"> <metal:content-core define-macro="content-core"> <span tal:replace="structure context/@@authenticator/authenticator"/> <div class="pat-structure" tal:attributes="data-pat-structure view/options" /> </metal:content-core> </metal:content-core>上述文件路径:plone.app.content/plone/app/content/browser/contents/templates/folder_contents.pt
- folder_contents.pt调用视图类FolderContentsView的get_options方法 构建 所指向html部件的data-pat-structure属性值
def get_options(self): site = get_top_site_from_url(self.context, self.request) base_url = site.absolute_url() base_vocabulary = '%s/@@getVocabulary?name=' % base_url site_path = site.getPhysicalPath() context_path = self.context.getPhysicalPath() columns = self.get_columns() options = { 'vocabularyUrl': '%splone.app.vocabularies.Catalog' % ( base_vocabulary), 'urlStructure': { 'base': base_url, 'appended': '/folder_contents' }, 'moveUrl': '%s{path}/fc-itemOrder' % base_url, 'indexOptionsUrl': '%s/@@qsOptions' % base_url, 'contextInfoUrl': '%s{path}/@@fc-contextInfo' % base_url, 'setDefaultPageUrl': '%s{path}/@@fc-setDefaultPage' % base_url, 'availableColumns': columns, 'attributes': ['Title', 'path', 'getURL', 'getIcon', 'getMimeIcon', 'portal_type'] + list(columns.keys()), # noqa 'buttons': self.get_actions(), 'rearrange': { 'properties': self.get_indexes(), 'url': '%s{path}/@@fc-rearrange' % base_url }, 'basePath': '/' + '/'.join(context_path[len(site_path):]), 'upload': { 'relativePath': 'fileUpload', 'baseUrl': base_url, 'initialFolder': IUUID(self.context, None), 'useTus': TUS_ENABLED }, 'thumb_scale': self.get_thumb_scale(), } return options def __call__(self): self.options = json_dumps(self.get_options()) return super(FolderContentsView, self).__call__()上述文件路径为:plone.app.content/plone/app/content/browser/contents/__init__py
- 通过mockup包功能由提供的data-pat-structure属性构建动态页面(这一部分,完全由前端js操作,发出多个AJAX调用,构建动态页面)
/* Structure pattern. * * Options: * vocabularyUrl(string): Url to return query results (null) * indexOptionsUrl(string): Url to configure querystring widget with (null) * upload(string): upload configuration settings(null) * moveUrl(string): For supporting drag drop reordering (null) * contextInfoUrl(string): For supporting add menu (null) * * Documentation: * # Example * * {{ example-1 }} * * Example: example-1 * <div class="pat-structure" * data-pat-structure="vocabularyUrl:/relateditems-test.json; * uploadUrl:/upload; * moveUrl:/moveitem; * indexOptionsUrl:/tests/json/queryStringCriteria.json; * contextInfoUrl:{path}/context-info;"></div> */ define([ 'jquery', 'underscore', 'pat-base', 'mockup-patterns-structure-url/js/views/app' ], function($, _, Base, AppView) { 'use strict'; var Structure = Base.extend({ name: 'structure', trigger: '.pat-structure', parser: 'mockup', defaults: { // for implementing history changes // Example: {base: 'http://mysite.com', appended: '/folder_contents'} urlStructure: null, vocabularyUrl: null, indexOptionsUrl: null, // for querystring widget contextInfoUrl: null, // for add new dropdown and other info setDefaultPageUrl: null, menuOptions: null, // default action menu options per item. menuGenerator: 'mockup-patterns-structure-url/js/actionmenu', // default menu generator backdropSelector: '.plone-modal', // Element upon which to apply backdrops used for popovers activeColumnsCookie: 'activeColumns', /* As the options operate on a merging basis per new attribute (key/value pairs) on the option Object in a recursive fashion, array items are also treated as Objects so that custom options are replaced starting from index 0 up to the length of the array. In the case of buttons, custom buttons are simply replaced starting from the first one. The following defines the customized attributes that should be replaced wholesale, with the default version prefixed with `_default_`. */ attributes: null, _default_attributes: [ 'CreationDate', 'EffectiveDate', 'ExpirationDate', 'exclude_from_nav', 'getIcon', 'getMimeIcon', 'getObjSize', 'getURL', 'id', 'is_folderish', 'last_comment_date', 'ModificationDate', 'path', 'portal_type', 'review_state', 'Subject', 'Title', 'total_comments', 'UID' ], activeColumns: null, _default_activeColumns: [ 'ModificationDate', 'EffectiveDate', 'review_state' ], availableColumns: null, _default_availableColumns: { 'id': 'ID', 'ModificationDate': 'Last modified', 'EffectiveDate': 'Published', 'ExpirationDate': 'Expiration', 'CreationDate': 'Created', 'review_state': 'Review state', 'Subject': 'Tags', 'portal_type': 'Type', 'is_folderish': 'Folder', 'exclude_from_nav': 'Excluded from navigation', 'getObjSize': 'Object Size', 'last_comment_date': 'Last comment date', 'total_comments': 'Total comments' }, // action triggered for the primary link for each table row. tableRowItemAction: null, _default_tableRowItemAction: { folder: ['mockup-patterns-structure-url/js/navigation', 'folderClicked'], other: [] }, typeToViewAction: null, _default_typeToViewAction: { 'File': '/view', 'Image': '/view', 'Blob': '/view' }, collectionConstructor: 'mockup-patterns-structure-url/js/collections/result', momentFormat: 'L LT', rearrange: { properties: { 'id': 'ID', 'sortable_title': 'Title' }, url: '/rearrange' }, moveUrl: null, buttons: null, _default_buttons: [{ tooltip: 'Cut', title: 'Cut', url: '/cut' },{ tooltip: 'Copy', title: 'Copy', url: '/copy' },{ tooltip: 'Paste', title: 'Paste', url: '/paste' },{ tooltip: 'Delete', title: 'Delete', url: '/delete', context: 'danger', icon: 'trash' },{ tooltip: 'Workflow', title: 'Workflow', url: '/workflow' },{ tooltip: 'Tags', title: 'Tags', url: '/tags' },{ tooltip: 'Properties', title: 'Properties', url: '/properties' },{ tooltip: 'Rename', title: 'Rename', url: '/rename' }], datatables_options: {}, upload: { uploadMultiple: true, showTitle: true } }, init: function() { var self = this; /* This part replaces the undefined (null) values in the user modifiable attributes with the default values. May want to consider moving the _default_* values out of the options object. */ var replaceDefaults = ['attributes', 'activeColumns', 'availableColumns', 'buttons', 'typeToViewAction']; _.each(replaceDefaults, function(idx) { if (self.options[idx] === null) { self.options[idx] = self.options['_default_' + idx]; } }); var mergeDefaults = ['tableRowItemAction']; _.each(mergeDefaults, function(idx) { var old = self.options[idx]; self.options[idx] = $.extend( false, self.options['_default_' + idx], old ); }); self.browsing = true; // so all queries will be correct with QueryHelper self.options.collectionUrl = self.options.vocabularyUrl; self.options.pattern = self; // the ``attributes`` options key is not compatible with backbone, // but queryHelper that will be constructed by the default // ResultCollection will expect this to be passed into it. self.options.queryHelperAttributes = self.options.attributes; delete self.options.attributes; self.view = new AppView(self.options); self.$el.append(self.view.render().$el); } }); return Structure; });上述文件路径:mockup/patterns/structure/pattern.js