/*
* Copyright 2012 OSBI Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Sets up workspace drop zones for DnD and other interaction
*/
var WorkspaceDropZone = Backbone.View.extend({
template: function() {
var template = $("#template-workspace-dropzones").html() || "";
return _.template(template)();
},
events: {
'sortbeforestop .fields_list_body': 'select_dimension',
'click .d_dimension span.selections': 'selections',
'click .d_dimension a': 'selections',
'click .d_measure a' : 'remove_dimension',
'click .d_measure span.sort' : 'sort_measure',
'click .d_dimension span.sort' : 'sort_measure',
'click .limit' : 'limit_axis',
'click .clear_axis' : 'clear_axis'
},
initialize: function(args) {
// Keep track of parent workspace
this.workspace = args.workspace;
// Maintain `this` in jQuery event handlers
_.bindAll(this, "select_dimension", "move_dimension",
"remove_dimension", "update_selections","sort_measure", "limit_axis", "set_query_axis", "set_query_axis_filter", "set_query_axis_sort");
},
render: function() {
// Generate drop zones from template
$(this.el).html(this.template());
// Activate drop zones
$(this.el).find('.connectable').sortable({
connectWith: $(this.el).find('.connectable'),
forcePlaceholderSize: true,
forceHelperSize: true,
items: '> li',
opacity: 0.60,
placeholder: 'placeholder',
tolerance: 'touch',
start: function(event, ui) {
ui.placeholder.text(ui.helper.text());
}
});
return this;
},
limit_axis: function(event) {
var self = this;
if (typeof this.workspace.query == "undefined") {
return false;
}
if (this.workspace.query.get('type') != 'QM' || Settings.MODE == "view") {
return false;
}
var $target = $(event.target).hasClass('limit') ? $(event.target) : $(event.target).parent();
var $axis = $target.siblings('.fields_list_body');
var source = "";
var target = "ROWS";
if ($axis.hasClass('rows')) { target = "ROWS"; }
if ($axis.hasClass('columns')) { target = "COLUMNS"; }
if ($axis.hasClass('filter')) { target = "FILTER"; }
$body = $(document);
//$body.off('.contextMenu .contextMenuAutoHide');
//$('.context-menu-list').remove();
$.contextMenu('destroy', '.limit');
$.contextMenu({
appendTo: $target,
selector: '.limit',
ignoreRightClick: true,
build: function($trigger, e) {
var query = self.workspace.query;
var schema = query.get('schema');
var cube = query.get('connection') + "/" +
query.get('catalog') + "/"
+ ((schema == "" || schema == null) ? "null" : schema)
+ "/" + query.get('cube');
var items = {};
var measures = Saiku.session.sessionworkspace.measures[cube].get('data');
var func, n, sortliteral, filterCondition, sortOrder, sortOrderLiteral;
var sortHl, topHl, filterHl;
var isFilter = false;
var isSort = false;
var isTop = false;
var axes = self.workspace.query.get('axes');
_.each(axes, function(a) {
if (a.name == target) {
func = a.limitFunction;
n = a.limitFunctionN;
sortliteral = a.limitFunctionSortLiteral;
filterCondition = a.filterCondition;
isTop = (a.limitFunction != null);
isFilter = (a.filterCondition != null);
isSort = (a.sortOrder != null);
sortOrder = a.sortOrder;
sortOrderLiteral = a.sortOrderLiteral;
}
});
if (func != null && sortliteral == null) {
topHl = func + "###SEPARATOR###" + n;
} else if (func != null && sortliteral != null && n != null) {
topHl = "custom";
}
if (isSort && sortOrder != null) {
sortHl = "customsort";
}
_.each(measures, function(measure) {
items[measure.uniqueName] = {
name: measure.caption,
payload: {
"n" : 10,
"sortliteral" : measure.uniqueName
}
};
});
var addFun = function(items, fun) {
var ret = {};
for (key in items) {
ret[ (fun + '###SEPARATOR###'+ key) ] = _.clone(items[key]);
ret[ (fun + '###SEPARATOR###' + key) ].fun = fun;
if (fun == func && sortliteral == key && items[key].payload["n"] == n) {
topHl = fun + "Quick";
ret[ (fun + '###SEPARATOR###' + key) ].name =
"" + items[key].name + "";
}
if (fun == sortOrder && sortOrderLiteral == key) {
sortHl = fun + "Quick";
ret[ (fun + '###SEPARATOR###' + key) ].name =
"" + items[key].name + "";
}
}
return ret;
};
var citems = {
"filter" : {name: "Filter", items:
{
"customfilter": {name: "Custom..." },
"clearfilter": {name: "Clear Filter" }
}},
"limit" : {name: "Limit", items:
{
"TopCount###SEPARATOR###10": {name: "Top 10" },
"BottomCount###SEPARATOR###10": {name: "Bottom 10" },
"TopCountQuick" : { name: "Top 10 by...", items: addFun(items, "TopCount") },
"BottomCountQuick" : { name: "Bottom 10 by...", items: addFun(items, "BottomCount") },
"customtop" : {name: "Custom Limit..." },
"clearlimit" : {name: "Clear Limit"}
}},
"sort" : {name: "Sort", items:
{
"ASCQuick": {name: "Ascending" , items: addFun(items, "ASC") },
"DESCQuick": {name: "Descending", items: addFun(items, "DESC")},
"BASCQuick": {name: "Ascending (Breaking Hierarchy)", items: addFun(items, "BASC")},
"BDESCQuick": {name: "Descending (Breaking Hierarchy)", items: addFun(items, "BDESC") },
"customsort" : { name: "Custom..." },
"clearsort" : {name: "Clear Sort" }
}}
};
items["10"] = {
payload: { "n" : 10 }
}
if (isFilter) {
var f = citems["filter"];
f.name = "" + f.name + "";
f.items["customfilter"].name = "" + f.items["customfilter"].name + "";
}
if (isSort) {
var s = citems["sort"].items;
citems["sort"].name = "" + citems["sort"].name + "";
if (sortHl in s) {
s[sortHl].name = "" + s[sortHl].name + "";
}
}
if (isTop) {
var t = citems["limit"].items;
citems["limit"].name = "" + citems["limit"].name + "";
if (topHl in t) {
t[topHl].name = "" + t[topHl].name + "";
}
}
/**
if (quick in citems) {
citems[quick].name = "" + citems[quick].name + "";
}
*/
return {
callback: function(key, options) {
if (key == "clearfilter") {
$target.removeClass('on');
var url = "/axis/" + target + "/filter";
self.set_query_axis_filter(target, null);
self.workspace.query.action.del(url, {
success: self.workspace.query.run
});
} else if (key == "customfilter") {
var save_custom = function(filterCondition) {
self.set_query_axis_filter(target, filterCondition);
var url = "/axis/" + target + "/filter/" ;
self.workspace.query.action.post(url, {
success: self.workspace.query.run, data : { filterCondition: filterCondition }
});
};
(new FilterModal({
axis: target,
success: save_custom,
query: self.workspace.query,
expression: filterCondition,
expressionType: "Filter"
})).render().open();
} else if (key == "clearlimit") {
$target.removeClass('on');
var url = "/axis/" + target + "/limit";
self.set_query_axis(target, null, null, "");
self.workspace.query.action.del(url, {
success: self.workspace.query.run
});
} else if (key == "customtop") {
var save_custom = function(fun, n, sortliteral) {
self.set_query_axis(target, fun, n, sortliteral);
var url = "/axis/" + target + "/limit/" + fun;
self.workspace.query.action.post(url, {
success: self.workspace.query.run, data : { n: n, sortliteral: sortliteral }
});
};
(new CustomFilterModal({
axis: target,
measures: measures,
success: save_custom,
query: self.workspace.query,
func: func,
n: n,
sortliteral: sortliteral
})).render().open();
} else if (key == "customsort") {
var save_customsort = function(sortO, sortL) {
self.set_query_axis_sort(target, sortO, sortL);
var url = "/axis/" + target + "/sort/" + sortO + "/" + encodeURIComponent(sortL);
self.workspace.query.action.post(url, {
success: self.workspace.query.run
});
};
(new FilterModal({
axis: target,
success: save_customsort,
query: self.workspace.query,
expression: sortOrderLiteral,
expressionType: "Order"
})).render().open();
} else if (key == "clearsort") {
$target.removeClass('on');
var url = "/axis/" + target + "/sort";
self.set_query_axis_sort(target, null, null);
self.workspace.query.action.del(url, {
success: self.workspace.query.run
});
} else {
var fun = key.split('###SEPARATOR###')[0];
var ikey = key.split('###SEPARATOR###')[1];
var method = "";
var data = {};
if (_.indexOf(["ASC", "BASC", "DESC", "BDESC"], fun) > -1) {
method = "sort";
self.set_query_axis_sort(target, fun, items[ikey].payload["sortliteral"]);
fun += "/" + encodeURIComponent(items[ikey].payload["sortliteral"]);
} else {
method = "limit";
self.set_query_axis(target, fun, items[ikey].payload.n , items[ikey].payload["sortliteral"]);
data = items[ikey].payload;
}
var url = "/axis/" + target + "/" + method + "/" + fun;
self.workspace.query.action.post(url, {
success: self.workspace.query.run, data : data
});
}
},
items: citems
}
}
});
$target.contextMenu();
},
set_query_axis_filter: function(target, filterCondition) {
var self = this;
var axes = this.workspace.query.get('axes');
_.each(axes, function(axis) {
if (axis.name == target) {
axis.filterCondition = filterCondition;
if (axis.limitFunction != null || axis.filterCondition != null || axis.sortOrder != null) {
$(self.el).find('.fields_list[title="' + target + '"] .limit').addClass('on');
} else {
$(self.el).find('.fields_list[title="' + target + '"] .limit').removeClass('on');
}
return false;
}
});
return false;
},
set_query_axis_sort: function(target, sortOrder, sortLiteral ) {
var self = this;
var axes = this.workspace.query.get('axes');
_.each(axes, function(axis) {
if (axis.name == target) {
axis.sortOrder = sortOrder;
axis.sortOrderLiteral = sortLiteral;
if (axis.limitFunction != null || axis.filterCondition != null || axis.sortOrder != null) {
$(self.el).find('.fields_list[title="' + target + '"] .limit').addClass('on');
} else {
$(self.el).find('.fields_list[title="' + target + '"] .limit').removeClass('on');
}
return false;
}
});
return false;
},
set_query_axis: function(target, func, n, sortliteral) {
var self = this;
var axes = this.workspace.query.get('axes');
_.each(axes, function(axis) {
if (axis.name == target) {
axis.limitFunction = func;
axis.limitFunctionN = n;
axis.limitFunctionSortLiteral = sortliteral;
if (axis.limitFunction != null || axis.filterCondition != null || axis.sortOrder != null) {
$(self.el).find('.fields_list[title="' + target + '"] .limit').addClass('on');
} else {
$(self.el).find('.fields_list[title="' + target + '"] .limit').removeClass('on');
}
return false;
}
});
return false;
},
clear_axis: function(event) {
var self = this;
if (typeof this.workspace.query == "undefined") {
return false;
}
if (this.workspace.query.get('type') != 'QM' || Settings.MODE == "view") {
return false;
}
var $target = $(event.target);
var $axis = $target.siblings('.fields_list_body');
var source = "";
var target = "";
if ($axis.hasClass('rows')) { target = "ROWS"; }
if ($axis.hasClass('columns')) { target = "COLUMNS"; }
if ($axis.hasClass('filter')) { target = "FILTER"; }
var url = "/axis/" + target;
self.workspace.query.action.del(url, {
success: function(model, response) {
$axis.find('.connectable').empty();
self.workspace.query.parse(response);
self.workspace.sync_query();
}
});
event.preventDefault();
return false;
},
sort_measure: function(event, ui) {
var $axis = $(event.target).parent().parents('.fields_list_body');
var source = "";
var target = "ROWS";
if ($axis.hasClass('rows')) { source = "ROWS"; target= "COLUMNS"; }
if ($axis.hasClass('columns')) { source = "COLUMNS"; target="ROWS"; }
if ($axis.hasClass('filter')) { source = "FILTER"; target="COLUMNS"; }
var sortOrder = "";
if ($(event.target).hasClass('none')) sortOrder = "none";
if ($(event.target).hasClass('BASC')) sortOrder = "BASC";
if ($(event.target).hasClass('BDESC')) sortOrder = "BDESC";
var memberpath = $(event.target).parent().find('a').attr('href').replace('#', '').split('/');
var member = "-";
if ($(event.target).parent().hasClass('d_dimension')) {
member = memberpath[2] + ".CurrentMember.Name";
$axis.find('.d_dimension .sort').removeClass('BASC').removeClass('BDESC').addClass('none');
$axis.parent().parent().find("." + target.toLowerCase() + " .d_measure .sort").removeClass('BASC').removeClass('BDESC').addClass('none');
target = source;
} else {
member = memberpath[memberpath.length -1];
$axis.find('.d_measure .sort').removeClass('BASC').removeClass('BDESC').addClass('none');
$axis.parent().parent().find("." + target.toLowerCase() + " .d_dimension .sort").removeClass('BASC').removeClass('BDESC').addClass('none');
}
var futureSortOrder = "none";
if (sortOrder == "none") futureSortOrder = "BASC";
if (sortOrder == "BASC") futureSortOrder = "BDESC";
if (sortOrder == "BDESC") futureSortOrder = "none";
$(event.target).removeClass('none').addClass(futureSortOrder);
if (futureSortOrder == "none") {
var url = "/axis/" + target + "/sort/";
this.workspace.query.action.del(url, {
success: this.workspace.query.run
});
} else {
var url = "/axis/" + target + "/sort/" + futureSortOrder + "/" + member;
this.workspace.query.action.post(url, {
success: this.workspace.query.run
});
}
},
select_dimension: function(event, ui) {
/*
$('.workspace_fields').css('height','');
var wh = $('.workspace_fields').height();
$('.workspace_fields').css('height', wh);
if ($axis.length == 0) {
$axis = $('.workspace_fields .placeholder').parents('.fields_list_body');
}
// total width - fieldslist header + padding 15 - clear icon width
var bodyWidth = ww - $axis.siblings('.fields_list_header').width() - 15 - $axis.siblings('.clear_axis').width();
$axis.width(bodyWidth);
var axisHeight = $axis.height() ? $axis.height() : 0;
if (axisHeight > 40) {
$axis.siblings('.fields_list_header').height($axis.height() - 6);
} else {
$axis.siblings('.fields_list_header').css('height','');
}
*/
var $axis = ui.item.parents('.fields_list_body');
var target = "";
if ($axis.hasClass('rows')) target = "ROWS";
if ($axis.hasClass('columns')) target = "COLUMNS";
if ($axis.hasClass('filter')) target = "FILTER";
// Short circuit if this is a move
if (ui.item.hasClass('d_measure') ||
ui.item.hasClass('d_dimension')) {
this.move_dimension(event, ui, target);
return;
}
// Make the element and its parent bold
var original_href = ui.item.find('a').attr('href');
var $original = $(this.workspace.el).find('.sidebar')
.find('a[href="' + original_href + '"]').parent('li');
$original
.css({fontWeight: "bold"})
.draggable('disable');
$original.parents('.parent_dimension')
.find('.folder_collapsed')
.css({fontWeight: "bold"});
// Wrap with the appropriate parent element
if (ui.item.find('a').hasClass('level')) {
var $icon = $("").addClass('sprite selections');
var $icon2 = $("").addClass('sprite sort none');
ui.item.addClass('d_dimension').prepend($icon);
$icon2.insertBefore($icon);
} else {
var $icon = $("").addClass('sort none');
ui.item.addClass('d_measure').prepend($icon);
}
var member = ui.item.find('a').attr('href').replace('#', '');
var dimension = member.split('/')[0];
var dimensions = [];
this.update_selections(event,ui);
$axis.find('a').each( function(i,element) {
var imember = $(element).attr('href');
var idimension = imember.replace('#', '').split('/')[0];
if (dimensions.indexOf(idimension) == -1) {
dimensions.push(idimension);
}
});
var index = dimensions.indexOf(dimension);
// Notify the model of the change
this.workspace.query.move_dimension(member,
target, index);
if ("FILTER" == target && ui.item.hasClass('d_dimension')) {
var ev = { target : $axis.find('a[href="#' + member + '"]') };
this.selections(ev, ui);
}
// Prevent workspace from getting this event
return true;
},
move_dimension: function(event, ui, target) {
if (! ui.item.hasClass('deleted')) {
var $axis = ui.item.parents('.fields_list_body');
// Notify the model of the change
var dimension = ui.item.find('a').attr('href').replace('#', '').split('/')[0];
var dimensions = [];
this.update_selections(event,ui);
$axis.find('a').each( function(i,element) {
var imember = $(element).attr('href');
var idimension = imember.replace('#', '').split('/')[0];
if (dimensions.indexOf(idimension) == -1) {
dimensions.push(idimension);
}
});
var index = dimensions.indexOf(dimension);
this.workspace.query.move_dimension(dimension,
target, index);
}
// Prevent workspace from getting this event
event.stopPropagation();
return false;
},
update_selections: function(event, ui) {
var member = ui.item.find('a').attr('href');
var dimension = member.replace('#', '').split('/')[0];
var index = ui.item.parent('.connectable').children().index(ui.item);
var $axis = ui.item.parents('.fields_list_body');
var allAxes = $axis.parent().parent();
var target = '';
var source = '';
var myself = this;
var $originalItem = $(myself.workspace.el).find('.sidebar')
.find('a[href="' + member + '"]').parent();
var insertElement = $(ui.item);
var type = $(ui.item).hasClass('d_dimension') ? "d_dimension" : "d_measure";
var sourceAxis = "";
if ($axis.hasClass('rows')) sourceAxis = "ROWS";
if ($axis.hasClass('columns')) sourceAxis = "COLUMNS";
if ($axis.hasClass('filter')) sourceAxis = "FILTER";
source = ".rows, .columns, .filter";
allAxes.find(source).find('a').each( function(index, element) {
var p_member = $(element).attr('href').replace('#', '');
var p_dimension = p_member.split('/')[0];
if (p_dimension == dimension && (( "#" + p_member) != member )) {
$(element).parent().remove();
}
});
var n_dimension = null;
var p_dimension = null;
var prev = $(ui.item).prev();
if (prev && prev.length > 0) {
var p_member = prev.find('a').attr('href');
p_dimension = p_member.replace('#', '').split('/')[0];
}
var next = $(ui.placeholder).next();
while (p_dimension != null && next && next.length > 0 ) {
var n_member = next.find('a').attr('href');
n_dimension = n_member.replace('#', '').split('/')[0];
if (p_dimension == n_dimension) {
next.insertBefore($(ui.item));
} else {
p_dimension = null;
}
next = $(ui.placeholder).next();
}
$originalItem.parent().find('.ui-draggable-disabled').clone().attr('class', 'ui-draggable').removeAttr('style')
.addClass(type)
.insertAfter(insertElement);
$axis.find('.d_dimension a').each( function(index, element) {
element = $(element);
if (!element.prev() || (element.prev() && element.prev().length == 0)) {
var $icon = $("").addClass('sprite sort none');
$icon.insertBefore(element);
var $icon = $("").addClass('sprite selections');
$icon.insertBefore(element);
}
});
$axis.find('.d_measure a, .d_dimension a').each( function(index, element) {
element = $(element);
if (!element.prev() || (element.prev() && element.prev().length == 0)) {
if (sourceAxis != "FILTER") {
var $icon = $("").addClass('sort none');
$icon.insertBefore(element);
}
}
});
$(ui.item).remove();
$(this.workspace.el).find('.fields_list_body').each(function(idx, ael) {
var $axis = $(ael);
if ($axis.find('li').length == 0) {
$axis.siblings('.clear_axis').addClass('hide');
} else {
$axis.siblings('.clear_axis').removeClass('hide');
}
});
return false;
},
remove_dimension: function(event, ui) {
// Reenable original element
var $source = ui ? ui.draggable : $(event.target).parent();
var original_href = $source.find('a').attr('href');
var $original = $(this.workspace.el).find('.sidebar')
.find('a[href="' + original_href + '"]').parent('li');
$original
.draggable('enable')
.css({ fontWeight: 'normal' });
// Unhighlight the parent if applicable
if ($original.parents('.parent_dimension')
.children().children('.ui-state-disabled').length === 0) {
$original.parents('.parent_dimension')
.find('.folder_collapsed')
.css({fontWeight: "normal"});
}
// Notify server
var target = '';
var dimension = original_href.replace('#', '');
$target_el = $source.parent().parent('div.fields_list_body');
if ($target_el.hasClass('rows')) target = "ROWS";
if ($target_el.hasClass('columns')) target = "COLUMNS";
if ($target_el.hasClass('filter')) target = "FILTER";
var url = "/axis/" + target + "/dimension/" + dimension;
this.workspace.query.action.del(url, {
success: this.workspace.query.run
});
// Remove element
$source.addClass('deleted').remove();
if ($target_el.find('li.d_dimension, li.d_measure, li.ui-draggable').length == 0) {
$target_el.siblings('.clear_axis').addClass('hide');
}
// Prevent workspace from getting this event
event.stopPropagation();
event.preventDefault();
return false;
},
selections: function(event, ui) {
// Determine dimension
var $target = $(event.target).hasClass('sprite') ?
$(event.target).parent().find('.level') :
$(event.target);
var key = $target.attr('href').replace('#', '');
// Launch selections dialog
(new SelectionsModal({
target: $target,
name: $target.text(),
key: key,
workspace: this.workspace
})).open();
// Prevent default action
try {
event.preventDefault();
} catch (e) { }
return false;
}
});