Skip to content

Commit

Permalink
Merge pull request #618 from plone/metatoaster-structure-master
Browse files Browse the repository at this point in the history
WIP: Making structure pattern more flexible to customization options
  • Loading branch information
thet committed Mar 16, 2016
2 parents 477a80f + 4fa0384 commit ba76b86
Show file tree
Hide file tree
Showing 17 changed files with 2,613 additions and 280 deletions.
36 changes: 35 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Changelog
=========

2.1.4 (unreleased)
2.2.0 (unreleased)
------------------

Incompatibilities:
Expand All @@ -13,11 +13,45 @@ New:
- set XML syntax coloring for .pt files in text editor
[ebrehault]

- Structure now accept customization options for a number of things in
the form of requirejs modules. This currently includes the extended
menuOptions definition, the menuGenerator per result item, the click
handler the link for each individual item, and the collection module
for interaction with the server side API for item generation.

Where applicable, the default implementation are now named requirejs
includes with those as the defaults to the relevant parameters.

Incidentally, this also required a major cleanup/refactoring of how
the ResultCollection class interacts with the pattern and its support
classes.
[metatoaster]

- Structure now supports IPublishTraverse style subpaths for push state.
[metatoaster]

- Alternative parameter/syntax for specification of the pushState url to
be inline with the usage of ``{path}`` token in URL templates.
[metatoaster]

- Structure can use the ``viewURL`` from a returned data item, alongside
with the previous default of simply appending ``/view`` to the
``getURL`` attribute if this was not provided, for its view URL,
[metatoaster]

Fixes:

- Fix ``Makefile`` to use ``mockup/build`` instead of ``build``.
[thet]

- Fix structure so rendering does not fail when paste button is missing.
[metatoaster]

- Fix structure so that different views can have its own saved visible
column ordering settings. Also loosen the coupling of the columns to
the data to aid in view rendering.
[metatoaster]


2.1.3 (2016-02-27)
New:
Expand Down
9 changes: 9 additions & 0 deletions mockup/js/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ define([
.toString(16).substring(1));
};

var getWindow = function() {
var win = window;
if (win.parent !== window) {
win = win.parent;
}
return win;
};

return {
generateId: generateId,
parseBodyTag: function(txt) {
Expand Down Expand Up @@ -309,6 +317,7 @@ define([
return $el.val();
}
},
getWindow: getWindow,
featureSupport: {
/*
well tested feature support for things we use in mockup.
Expand Down
93 changes: 93 additions & 0 deletions mockup/patterns/structure/js/actionmenu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
define([
], function() {
'use strict';

var menuOptions = {
'cutItem': [
'mockup-patterns-structure-url/js/actions',
'cutClicked',
'#',
'Cut',
],
'copyItem': [
'mockup-patterns-structure-url/js/actions',
'copyClicked',
'#',
'Copy'
],
'pasteItem': [
'mockup-patterns-structure-url/js/actions',
'pasteClicked',
'#',
'Paste'
],
'move-top': [
'mockup-patterns-structure-url/js/actions',
'moveTopClicked',
'#',
'Move to top of folder'
],
'move-bottom': [
'mockup-patterns-structure-url/js/actions',
'moveBottomClicked',
'#',
'Move to bottom of folder'
],
'set-default-page': [
'mockup-patterns-structure-url/js/actions',
'setDefaultPageClicked',
'#',
'Set as default page'
],
'selectAll': [
'mockup-patterns-structure-url/js/actions',
'selectAll',
'#',
'Select all contained items'
],
'openItem': [
'mockup-patterns-structure-url/js/navigation',
'openClicked',
'#',
'Open'
],
'editItem': [
'mockup-patterns-structure-url/js/navigation',
'editClicked',
'#',
'Edit'
],
};

var ActionMenu = function(menu) {
// If an explicit menu was specified as an option to AppView, this
// constructor will not override that.
if (menu.menuOptions !== null) {
return menu.menuOptions;
}

var result = {};
result['cutItem'] = menuOptions['cutItem'];
result['copyItem'] = menuOptions['copyItem'];
if (menu.app.pasteAllowed && menu.model.attributes.is_folderish) {
result['pasteItem'] = menuOptions['pasteItem'];
}
if (!menu.app.inQueryMode() && menu.options.canMove !== false) {
result['move-top'] = menuOptions['move-top'];
result['move-bottom'] = menuOptions['move-bottom'];
}
if (!menu.model.attributes.is_folderish && menu.app.setDefaultPageUrl) {
result['set-default-page'] = menuOptions['set-default-page'];
}
if (menu.model.attributes.is_folderish) {
result['selectAll'] = menuOptions['selectAll'];
}
if (menu.options.header) {
result['openItem'] = menuOptions['openItem'];
}
result['editItem'] = menuOptions['editItem'];
return result;
};

return ActionMenu;
});
129 changes: 129 additions & 0 deletions mockup/patterns/structure/js/actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
define([
'jquery',
'underscore',
'backbone',
'mockup-patterns-structure-url/js/models/result',
'mockup-utils',
'translate',
], function($, _, Backbone, Result, utils, _t) {
'use strict';

// use a more primative class than Backbone.Model?
var Actions = Backbone.Model.extend({
initialize: function(options) {
this.options = options;
this.app = options.app;
this.model = options.model;
this.selectedCollection = this.app.selectedCollection;
},
selectAll: function(e){
// This implementation is very specific to the default collection
// with the reliance on its queryParser and queryHelper. Custom
// collection (Backbone.Paginator.requestPager implementation)
// will have to come up with their own action for this.
e.preventDefault();
var self = this;
var page = 1;
var count = 0;
var getPage = function(){
self.app.loading.show();
$.ajax({
url: self.app.collection.url,
type: 'GET',
dataType: 'json',
data: {
query: self.app.collection.queryParser({
searchPath: self.model.attributes.path
}),
batch: JSON.stringify({
page: page,
size: 100
}),
attributes: JSON.stringify(
self.app.collection.queryHelper.options.attributes)
}
}).done(function(data){
var items = self.app.collection.parse(data, count);
count += items.length;
_.each(items, function(item){
self.app.selectedCollection.add(new Result(item));
});
page += 1;
if(data.total > count){
getPage();
}else{
self.app.loading.hide();
self.app.tableView.render();
}
});
};
getPage();
},

doAction: function(buttonName, successMsg, failMsg){
var self = this;
$.ajax({
url: self.app.buttons.get(buttonName).options.url,
data: {
selection: JSON.stringify([self.model.attributes.UID]),
folder: self.model.attributes.path,
_authenticator: utils.getAuthenticator()
},
dataType: 'json',
type: 'POST'
}).done(function(data){
if(data.status === 'success'){
self.app.setStatus(_t(successMsg + ' "' + self.model.attributes.Title + '"'));
self.app.collection.pager();
self.app.updateButtons();
}else{
self.app.setStatus(_t('Error ' + failMsg + ' "' + self.model.attributes.Title + '"'));
}
});
},

cutClicked: function(e) {
var self = this;
e.preventDefault();
self.doAction('cut', _t('Cut'), _t('cutting'));
},
copyClicked: function(e) {
var self = this;
e.preventDefault();
self.doAction('copy', _t('Copied'), _t('copying'));
},
pasteClicked: function(e) {
var self = this;
e.preventDefault();
self.doAction('paste', _t('Pasted into'), _t('Error pasting into'));
},
moveTopClicked: function(e) {
e.preventDefault();
this.app.moveItem(this.model.attributes.id, 'top');
},
moveBottomClicked: function(e) {
e.preventDefault();
this.app.moveItem(this.model.attributes.id, 'bottom');
},
setDefaultPageClicked: function(e) {
e.preventDefault();
var self = this;
$.ajax({
url: self.app.getAjaxUrl(self.app.setDefaultPageUrl),
type: 'POST',
data: {
'_authenticator': $('[name="_authenticator"]').val(),
'id': this.model.attributes.id
},
success: function(data) {
self.app.ajaxSuccessResponse.apply(self.app, [data]);
},
error: function(data) {
self.app.ajaxErrorResponse.apply(self.app, [data]);
}
});
},
});

return Actions;
});
49 changes: 45 additions & 4 deletions mockup/patterns/structure/js/collections/result.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,58 @@ define([
'underscore',
'backbone',
'mockup-patterns-structure-url/js/models/result',
'mockup-utils',
'backbone.paginator'
], function(_, Backbone, Result) {
], function(_, Backbone, Result, Utils) {
'use strict';

var ResultCollection = Backbone.Paginator.requestPager.extend({
model: Result,
queryHelper: null, // need to set
initialize: function(models, options) {
this.options = options;
this.view = options.view;
this.url = options.url;
this.queryParser = options.queryParser;
this.queryHelper = options.queryHelper;

this.queryHelper = Utils.QueryHelper(
$.extend(true, {}, this.view.options, {
attributes: this.view.options.queryHelperAttributes}));

this.queryParser = function(options) {
var self = this;
if(options === undefined){
options = {};
}
var term = null;
if (self.view.toolbar) {
term = self.view.toolbar.get('filter').term;
}
var sortOn = self.view.sort_on; // jshint ignore:line
var sortOrder = self.view.sort_order; // jshint ignore:line
if (!sortOn) {
sortOn = 'getObjPositionInParent';
}
return JSON.stringify({
criteria: self.queryHelper.getCriterias(term, $.extend({}, options, {
additionalCriterias: self.view.additionalCriterias
})),
sort_on: sortOn,
sort_order: sortOrder
});
}

// check and see if a hash is provided for initial path
if (window.location.hash.substring(0, 2) === '#/') {
this.queryHelper.currentPath = window.location.hash.substring(1);
}

Backbone.Paginator.requestPager.prototype.initialize.apply(this, [models, options]);
},
getCurrentPath: function() {
return this.queryHelper.getCurrentPath();
},
setCurrentPath: function(path) {
this.queryHelper.currentPath = path;
},
pager: function() {
this.trigger('pager');
Backbone.Paginator.requestPager.prototype.pager.apply(this, []);
Expand All @@ -38,6 +76,9 @@ define([
// how many items per page should be shown
perPage: 15
},
// server_api are query parameters passed directly (currently GET
// parameters). These are currently generated using following
// functions. Renamed to queryParams in Backbone.Paginator 2.0.
server_api: {
query: function() {
return this.queryParser();
Expand Down
Loading

0 comments on commit ba76b86

Please sign in to comment.