/* DSC Kit Tree browser jQuery plugin */
(function($) {
var div;
var tree;
var opts;
var debug;
var methods = {
init : function(options) {
opts = $.extend({}, $.fn.dsc_tree.defaults, options);
div = $(this);
debug = (opts.debug===true);
opts.show_refresh_button = opts.refresh_button || true;
opts.hide_locked = opts.hide_locked || false;
opts.show_filter = opts.show_filter || true;
opts.show_move_buttons = opts.show_move_buttons || true;
opts.filter_on_path = opts.filter_on_path || false;
opts.open_level = opts.open_level || 0;
opts.initial_refresh = opts.initial_refresh || false;
opts.click_page = opts.click_page || "edit";
opts.mode = opts.mode || "editor";
fetch_data(opts.initial_refresh);
opts.is_popup = opts.mode==="popup";
},
get_node_data : function(id) {
return find_node(tree, 'c', id);
}
};
var node_template = _.template("
<%= node.t %>
");
var node_level;
var max_id = -1;
function fetch_data(refresh) {
$.get(opts.url, {refresh: refresh ? "1" : "0"}, function(json) {
tree = json;
tree.is_root = true;
redraw();
});
}
function l_id(li) {
var lid = $(li).attr('id');
return [lid.substring(0,1), lid.substring(2, lid.length)];
}
function find_li(type, id) {
return div.find('ul.tree #' + type + '_' + id);
}
function find_node_for_li(li) {
var lid = l_id(li);
var type = lid[0];
var id = lid[1];
return find_node(tree, type, id);
}
function find_node(n, type, id) {
if (n.y==type && n.id==id) { return n; }
if (n.c===undefined) { return null; }
for(var i=0; i");
if (opts.show_filter || opts.show_move_buttons) {
div.append(tree_options);
}
if (opts.show_filter) {
add_filter(tree_options);
}
if (opts.show_move_buttons && opts.is_popup===false) {
add_move_buttons(tree_options);
}
var listlist = $("");
var list = $("");
div.append(listlist);
div.append(list);
if (opts.show_refresh_button) {
add_refresh_button();
}
draw_node(tree, list, 0);
$('.dsc_tree').on('mouseenter', '.control, .title, .cog', function(event) {
hover_in_node(get_li_up(event));
}).on('mouseleave', '.control, .title, .cog', function(event) {
hover_out_node(get_li_up(event));
}).on('click', 'div.cog', function(event) {
$(event.target).parent('li').contextMenu({x:event.clientX,y:event.clientY});
event.stopPropagation();
}).on('click', 'li.type_c > div.control', function(event) {
toggle_node($(event.target).parent('li'));
event.stopPropagation();
});
$('.dsc_tree').on('click', 'li.type_s > div > span , li.type_p > div > span', function(event) {
click_node($(event.target).parent('div').parent('li'));
event.stopPropagation();
}).on('click', 'li.type_c > div > span', function(event) {
toggle_node($(event.target).parent('div').parent('li'));
event.stopPropagation();
});
if (opts.is_popup===false) {
$.contextMenu({selector:'.dsc_tree li',
build: function($trigger, e) {
return context_menu($trigger);
}
});
}
}
function context_menu(target) {
var li = target;
if (!li.is("li")) li = li.parents('li');
var node = find_node_for_li(li);
var content;
var menu;
if (node.y==='c') {
var has_children = node.c && node.c.length>0;
menu = {
'title1' : { html: "Category", icon:"category", type:"html" },
'separator1': '--' ,
'newcat' : { name: "New Category", callback: function(menuItem,menu) { new_sub_category(node, li)}, icon: "newcat" },
'newpage' : { name: 'New Page', callback: function(menuItem,menu) { document.location = '/page/new?cat_id=' + node.id },
icon: "newpage" } ,
'newpagestub' : { name: 'New Page Stub', callback: function(menuItem,menu) { new_stub(node, li); }, icon: "newpagestub" },
'separator1': '--' ,
'permissions' : { name: 'Permissions', callback: function(menuItem,menu) { document.location = '/category/' + node.id + '/permissions' }, icon: "permissions" },
'separator1': '--' ,
'rename' : {name: 'Rename', callback: function(menuItem,menu) { rename(li); }, icon:"rename", disabled: node.id==1, className: node.id==1 ? 'disabled':''} ,
'delete' : {name: 'Delete', callback: function(menuItem,menu) { delete_category(li); }, disabled: has_children, className: has_children ? 'disabled':'', icon: "catdelete" },
};
}
else {
var is_stub = node.y == 's';
var is_deleted = node.d;
menu = {}
if (node.y=='p') {
menu['title'] = { html: "Page", icon:"page", type: "html" };
menu['title2'] = { html: "Status: " + node.u + "", type: "html" };
menu['separator1'] = "----";
menu['view'] = { name: 'View', callback: function(menuItem,menu) { document.location = node.p; }, disabled: is_stub, className: is_stub ? 'disabled' : '', icon:"view"};
menu['edit'] = { name: 'Edit', callback: function(menuItem,menu) { document.location = node.p + "?edit=1"; }, disabled: is_stub, className: is_stub ? 'disabled' : '', icon:"edit" };
}
else {
menu['title'] = { html: "Page Stub", icon:"stub", type:"html" };
menu['separator1'] = "----";
}
menu['info'] = { name: 'View Info', callback: function(menuItem,menu) { document.location = '/page/' + node.id + '/info'; }, disabled: node.t=='s', className: node.t=='s' ? 'disabled' : '', icon:"info" } ;
if (node.d==1) {
menu['undelete'] = { name: 'Undelete', callback: function(menuItem,menu) { undelete_page(node,li); }, disabled: !is_deleted, className: is_deleted ? '' : 'disabled', icon:"undelete"};
} else {
menu['delete'] = { name: 'Delete', callback: function(menuItem,menu) { delete_page(node,li); }, disabled: is_deleted, className: is_deleted ? 'disabled' : '', icon:"delete"};
}
}
var r = { callback: function() {}, items:menu };
return r;
}
function delete_page(node,li) {
$.post("/page/" + node.id + "/delete", {}, function(resp) {
node.d = 1;
if (node.y=='s') {
remove_child(node);
li.remove();
}
style_node(li, node);
notify(resp.message);
});
}
function undelete_page(node,li) {
$.post("/page/" + node.id + "/undelete", {}, function(resp) {
node.d = 0;
li.removeClass("deleted");
li.find("div.control").removeClass("d_page").addClass("page");
notify(resp.message);
});
}
function click_node(clicked) {
var li = $(clicked);
var node = find_node_for_li(li);
if (node.y=='c') {
toggle_node(clicked);
}
else if (opts.mode==="popup") {
$('#' + opts.target_field, window.parent.document).val(node.p);
window.parent.close_link_browsers();
}
else {
if (node.y == 's') {
document.location = "/page/" + node.id + "/info";
}
else {
if (opts.click_page=='info') {
document.location = "/page/" + node.id + "/info";
}
else {
document.location = node.p + '?edit=1';
}
}
}
}
function hover_in_node(node) {
if (opts.is_popup===true) {
return;
}
var li = $(node);
if (li==cog_showing) {
return ;
}
if (cog_showing) {
hover_out_node(cog_showing);
}
cog_showing = li.find('div.cog').first();
if (!cog_showing.hasClass('cog_show')) {
cog_showing.addClass("cog_show");
}
}
var cog_showing = null;
function hover_out_node(node) {
var li = $(node);
li.find('div.cog').first().removeClass("cog_show");
}
function toggle_node(to_open) {
var li = $(to_open);
var node = find_node_for_li(li);
if (node.c==null || node.c.length==0) return;
if (node.is_open) {
close_node(node, li);
}
else {
open_node(node, li);
}
set_tree_state();
}
function open_node(node, li) {
if (node.is_open) {
return;
}
node.is_open = true;
li.find('> div').first().removeClass().addClass('control cat_open');
li.find('ul').first().show();
}
function close_node(node, li) {
if (!node.is_open) {
return;
}
node.is_open = false;
li.find('> div').first().removeClass().addClass('control cat_can_open');
li.find('> ul').first().hide();
}
function delete_category(li) {
var node = find_node_for_li(li);
if (node.is_new) {
notify("Category deleted");
}
else {
$.post("/category/delete/" + node.id, {}, function(resp) {
notify(resp.message);
});
}
// need to remove from LI and from node tree, then might need to change control icon of former parent...
remove_child(node);
li.remove();
}
function remove_child(node) {
var parent_li = find_li('c', node.parentid);
var parent_node = find_node(tree,'c',node.parentid);
var node_index = _.indexOf(parent_node.c, node);
parent_node.c[node_index] = false;
parent_node.c = _.compact(parent_node.c);
style_node(parent_li, parent_node);
}
function rename(li) {
var title = $(li).find('div.title').first();
var node = find_node_for_li(li);
title.html(' Cancel');
li.find('a').on('click', function(event) {
title.removeClass("not_saved");
var parent_node = find_node(tree, 'c', node.parentid);
if (node.is_new===true) {
remove_child(node);
li.remove();
}
else {
title.html(node.t);
}
event.stopPropagation();
});
li.find('input').focus().on('keyup', function(event) {
if (event.which==13) {
var entry = $(event.target).val();
title.addClass("not_saved");
if (node.is_new===false) {
var url = node.y=='c' ? "/category/rename" : "/page/stub/rename";
$.post(url + "/" + node.id, {name:entry}, function(resp) {
if (resp.okay===true) {
title.removeClass("not_saved");
node.t = resp.name;
title.html(resp.name);
node.is_new = false;
}
notify(resp.message);
});
}
else {
var url = node.y=='c' ? "/category/new" : "/page/stub";
$.post(url + "/" + node.parentid, {name:entry}, function(resp) {
if (resp.okay) {
title.html(resp.name);
title.removeClass("not_saved");
node.id = resp.id;
li.attr('id', node.y + "_" + node.id);
}
notify(resp.message);
});
}
}
}).focus();
}
function new_stub(parent_node, parent_li) {
new_item(parent_node, parent_li, 's');
style_node(parent_li, parent_node);
}
function new_sub_category(parent_node, parent_li) {
new_item(parent_node, parent_li, 'c');
style_node(parent_li, parent_node);
}
function new_item(parent_node, parent_li, type) {
var node = { t: "New " + (type=='c' ? "Category" :"Page Stub"),
y: type,
d: false,
c: [],
id: max_id + 1,
parentid: parent_node.id,
is_new: true,
extended: true,
is_open: false};
var new_li = add_node(node, parent_li);
if (!parent_node.is_open) {
toggle_node(parent_li);
}
rename(new_li);
}
function add_node(node, parent_li) {
var parent_node = find_node_for_li(parent_li);
parent_node.c.push(node);
var parent_ul = parent_li.find('ul').first();
if (parent_ul.length==0) {
parent_ul = $("");
parent_li.append(parent_ul);
}
return draw_node(node, parent_ul, parent_node.level + 1);
}
function style_node(li, node) {
var control_class = '';
var control_div = li.find('div.control').first();
if (node.y=='c') {
var has_children = node.c && node.c.length>0;
if (!has_children) {
node.is_open = false;
}
control_class = node.is_open ? 'cat_open' : (has_children ? 'cat_can_open' : 'cat_cant_open')
if (node.is_root) {
li.find('div.move').addClass('root_move');
}
}
else {
if (node.d==1) {
control_class = 'd_page'
li.addClass("deleted");
}
else {
control_class = node.y=='s' ? 'stub' : 'page';
}
if (node.b===true) {
li.addClass("pub");
}
}
control_div.removeClass("cat_open cat_can_open cat_cant_open").addClass(control_class);
}
function draw_node(node, list, level) {
if (node.id>max_id) {
max_id = node.id;
}
node.level = level;
var this_li = $(node_template({node: extend_node(node)}));
style_node(this_li, node);
if (opts.hide_locked==false || node.k!=true) {
list.append(this_li);
}
if (node.y=='c') {
var new_list_style = node.is_open ? '' : 'display: none;';
var new_list = $("");
this_li.append(new_list);
if (node.c && node.c.length>0) {
_.each(node.c, function(n) {
n.parentid = node.id;
draw_node(n, new_list, level + 1);
});
}
}
return this_li;
}
function extend_node(node) {
if (node.extended===undefined) {
if (node.is_open===undefined) {
node.is_open = (node.level <= opts.open_level);
}
node.extended = true;
node.is_new = false;
}
return node;
}
function load_tree_state() {
var state = $.cookie('tree');
if (state==null) {
return;
}
var nodes = state.split(",");
_.each(nodes, function(nid) {
var node = find_node(tree, 'c', nid);
if (node && node.c && node.c.length>0) {
node.is_open = true;
}
});
}
function set_tree_state() {
var l = []
var list = get_open_list(tree, l);
$.cookie("tree", list.join(','), {expires: 365, path: '/pages'})
}
function get_open_list(node, list) {
if (node.y!='c') {
return list;
}
if (node.is_open===true) {
list.push(node.id);
}
_.each(node.c, function(n) {
list = get_open_list(n, list);
});
return list
}
function add_refresh_button() {
div.append($('Refresh').on('click', function() {
fetch_data(true);
notify("Refreshed");
}));
}
function add_move_buttons(options_div) {
var buttons_div = $('');
options_div.append(buttons_div);
buttons_div.append($('Move Help'));
buttons_div.append($('Move').on('click', function() {
move_mode();
}));
buttons_div.append($('Copy').on('click', function() {
copy_mode();
}));
buttons_div.append($('Cancel').on('click', function() {
cancel_move();
}));
}
function cancel_move() {
div.find('div.buttons a.copy_icon').show();
div.find('div.buttons a.move_icon').show();
div.find('div.buttons a.cancel').hide();
div.find('li div.move').hide();
div.find('li.type_c > div.move').droppable('destroy');
div.find('.dd_accept').removeClass('dd_accept');
}
var dd = null;
function move_mode() {
dd = "move";
setup_dd();
}
function copy_mode() {
dd = "copy";
setup_dd();
}
function setup_dd() {
div.find('div.buttons a.copy_icon').hide();
div.find('div.buttons a.move_icon').hide();
div.find('div.buttons a.cancel').show();
div.find('li div.move').show().draggable({
addClasses: false,
revert: true
});
div.find('li.type_c > div.move').droppable({
over: function(event, ui) {
var li = get_li_up(event); //$(event.target).parent('li').first();
li.find('div.title').first().addClass("dd_accept");
},
out: function(event, ui) {
var li = get_li_up(event); // $(event.target).parent('li').first();
li.find('div.title').first().removeClass("dd_accept");
},
drop: function(event, ui) {
move($(ui.draggable).parent('li'), get_li_up(event));
}
});
}
function add_filter(options_div) {
options_div.append("");
options_div.find('input[name=filter]').on('keyup', function(event) {
do_filter();
}).focus();
}
function do_filter() {
var filter_el = div.find("input[name=filter]").first();
if (filter_el===undefined || filter_el===null) {
return;
}
var filter = filter_el.val();
if (filter.trim().length==0) {
div.find('ul.list').hide();
div.find('ul.tree').show();
return;
}
div.find('ul.tree').hide();
var list_el = div.find('ul.list');
list_el.html('');
list_el.show();
div.find('div.highlight').removeClass('highlight');
add_node_to_filtered_list(list_el, tree, filter);
}
function add_node_to_filtered_list(el, node, filter) {
if (node.t.indexOf(filter)>=0 || (node.g && node.g.indexOf(filter)>=0) || (opts.filter_on_path && node.p && node.p.indexOf(filter)>=0)) {
el.append("" + node.p + "").on('click', function(event) {
div.find('ul.list').hide();
div.find('ul.tree').show();
highlight_li($(event.target.parentElement));
});
}
_.each(node.c, function(n) {
add_node_to_filtered_list(el, n, filter);
});
}
function highlight_li(li) {
// walk up tree to root, opening as you go
var lid = l_id(li);
var lip = find_li(lid[0], lid[1]);
find_li(lid[0],lid[1]).find('div.title').first().addClass('highlight');
node = find_node_for_li(li);
if (node.y!='c') {
node = find_node(tree,'c',node.parentid);
}
var done = false;
while (!done) {
open_node(node, find_li('c',node.id));
if (node.is_root === undefined) {
node = find_node(tree,'c',node.parentid);
} else {
done = true;
}
}
}
function move(src, target) {
var src_lid = l_id(src);
var target_lid = l_id(target);
var src_node = find_node(tree, src_lid[0], src_lid[1]);
var target_node = find_node(tree, target_lid[0], target_lid[1]);
if (src_node.parentid == target_node.id) {
return;
}
if (src_node.y=='c') {
// walk up from target to root - if we find the source, disallow
//
var okay = true;
var node = target_node;
while (node!=tree) {
if (node.id == src_node.id) {
okay = false;
break;
}
node = find_node(tree, 'c', node.parentid);
}
if (!okay) {
notify("Sorry, you can't do this - it would leave an orphaned category");
return;
}
}
var move = dd=="move";
$.post("/category/move", { mode: dd, source_id: src_lid[1], target_id: target_lid[1], is_cat: src_lid[0]=='c' ? 1 : 0 }, function(resp) {
if (resp.okay) {
if (target_node.c===undefined) {
target_node.c = [];
}
if (move) {
remove_child(src_node);
src_node.parentid = target_node.id;
target_node.c.push(src_node);
target.find('ul').first().append(src);
}
else {
var copy_src_node = $.extend(true, {}, src_node);
copy_src_node.id = resp.new_id;
target_node.c.push(copy_src_node);
var new_li = src.clone();
new_li.attr("id", copy_src_node.y + "_" + resp.new_id);
target.find('ul').first().append(new_li);
}
open_node(target_node, target);
style_node(target, target_node);
cancel_move();
} else {
log("Move failed " + resp.message);
}
notify(resp.message);
});
cc = null;
}
function log(message) {
if (debug) {
console.debug(message);
}
}
$.fn.dsc_tree = function(method) {
if (methods[method]) {
return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
} else if ( typeof method === 'object' || ! method ) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on JQuery.dsc_tree');
}
}
})(jQuery);