Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Making structure pattern more flexible to customization options #618

Merged
merged 8 commits into from
Mar 16, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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