// Humpyard actions
;jQuery.humpyard || (function($) {
$.humpyard = {
dialog_count: 0,
ajax_dialog_commands: {
dialog: function(dialog, form, options) {
dialog.dialog('close');
},
replace: function(dialog, form, options) {
$.each(options, function(i,k){
var elem = $('#' + k['element']);
if(k['content']) {
elem.html(k['content']);
$.humpyard.initTreeView(elem);
}
if(k['url']) {
elem.load(k['url'], function(r, s, x) {
$.humpyard.initElements(elem);
elem.effect("highlight", {}, 2000);
});
}
});
},
insert: function(dialog, form, options) {
$.each(options, function(i,k){
var elem = $('
');
if(k['before']) {
elem.insertBefore($('#'+k['before']));
} else if(k['after']) {
elem.insertAfter($('#'+k['after']));
} else {
elem.appendTo($('#'+k['parent']+' div[data-droppable]:first'));
}
elem.load(k['url'], function(r, s, x) {
children = elem.children();
children.insertBefore(elem);
elem.remove();
$.humpyard.initElements(children);
children.effect("highlight", {}, 2000);
});
});
},
remove: function(dialog, form, options) {
$.each(options, function(i,k){
var elem = $('#' + k['element']);
elem.remove();
});
},
errors: function(dialog, form, options) {
$.each(options, function(attr, errors) {
errors = $.isArray(errors) ? errors : [errors];
$('.input.attr_' + attr + ' .field-highlight', form).addClass("ui-state-error");
field_errors = $('.input.attr_' + attr + ' .field-errors', form);
field_errors.append(errors.join(', '));
field_errors.fadeIn();
});
},
flash: function(dialog, form, options) {
var f = $('xxx
').html(options['content']).addClass(options['level']).hide();
if($('.flashes', form).size() > 0) {
$('.flashes', form).append(f)
} else {
$(form).prepend(f);
}
f.show('blind',300).delay(1800).hide('blind',300);
}
},
initEditButtons: function(elems) {
elems.each(function(idx, el){
var icon = $(el).attr('data-icon');
if (icon) {
$(el).button({text:false, icons: {primary:icon}});
} else {
$(el).button();
}
});
},
initSortables: function(elem, name, options) {
//$('div[data-sortable=' + name+ ']', elem).css('min-height','20px');
$('div[data-sortable=' + name+ ']', elem).addClass('droparea');
params = {
items: '> div[data-draggable=' + name+ ']',
connectWith: 'div[data-sortable=' + name+ ']',
placeholder: 'ui-state-highlight',
update: function(e, ui) {
var item = ui.item;
var sortable = item.parents('div[data-sortable=' + name+ ']:first');;
var parent = item.parents('div[data-draggable=' + name+ ']:first');
var prev = item.prev('div[data-draggable=' + name+ ']');
var next = item.next('div[data-draggable=' + name+ ']');
if(options.update) {
options.update(sortable, item, parent, prev, next);
}
}
};
if(options.handle) params.handle = options.handle;
$('div[data-sortable=' + name+ ']', elem).sortable(params);
},
tokenized_post: function(url, params) {
var csrf_token = $('meta[name=csrf-token]').attr('content'),
csrf_param = $('meta[name=csrf-param]').attr('content');
params[csrf_param] = csrf_token;
console.log("param: " + csrf_param);
console.log("token: " + params[csrf_param]);
$.post(url, params)
},
initPages: function(elem) {
$.humpyard.initSortables(elem, 'hy-pages', {
update: function(sortable, item, parent, prev, next) {
var params = {
id: item.attr('data-page-id'),
parent_id: parent.attr('data-page-id'),
prev_id: prev.attr('data-page-id'),
next_id: next.attr('data-page-id')
};
if(item.attr('data-page-type')) {
params['type'] = item.attr('data-page-type');
$.humpyard.dialog(item.attr('data-create-url'), {
get: params,
width: '600px',
modal: true
});
item.empty();
} else {
$.humpyard.tokenized_post(sortable.attr('data-sortable-update-url'), params);
}
}
});
},
initElements: function(elem) {
$.humpyard.initSortables(elem, 'hy-elements', {
handle: 'a[data-draghandle]',
update: function(sortable, item, parent, prev, next) {
var params = {
id: item.attr('data-element-id'),
page_id: $('#hy-body').attr('data-page-id'),
yield_name: item.parents('.hy-content:first').attr('data-content-yield'),
container_id: parent.attr('data-element-id'),
prev_id: prev.attr('data-element-id'),
next_id: next.attr('data-element-id')
};
if(item.attr('data-element-type')) {
params['type'] = item.attr('data-element-type');
$.humpyard.dialog(item.attr('data-create-url'), {
get: params,
width: '600px',
modal: true
});
item.empty();
} else {
$.humpyard.tokenized_post(sortable.attr('data-sortable-update-url'), params);
}
}
});
$.humpyard.initEditButtons($('.hy-el-menu a', elem));
},
initForm: function(elem) {
function detect_native(type) {
var i = document.createElement("input");
i.setAttribute("type", type);
return i.type !== "text";
}
// configure date pickers
if(!detect_native('date')) {
$('input[data-type=date]', elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true,
dateFormat: 'yy-mm-dd'
});
}
if(!detect_native('datetime')) {
$('input[data-type=datetime]', elem).datepicker({
showButtonPanel: true,
changeMonth: true,
changeYear: true,
dateFormat: 'yy-mm-dd'
});
}
},
initTabView: function(container) {
var tabview = $('.humpyard-tabview', container);
var tab_sources = $('.humpyard-tab', tabview);
var tabs = $('').prependTo(tabview);
var tabcount=0;
tab_sources.each(function(i,k){
tabcount++;
id = 'humpyard-' + $.humpyard.dialog_count + '-tab-' + tabcount;
$(k).attr('id', id)
$('' + $('.humpyard-tab-title',k).html() + '').append().appendTo(tabs);
$('.humpyard-tab-title',k).remove();
})
if(tabcount > 0) {
tabview.tabs();
}
},
initTreeView: function(container) {
var treeview = $('.humpyard-treeview', container);
treeview.bind("loaded.jstree", function (event, data) {
treeview.jstree("open_all");
// TODO: select current page in the tree
//treeview.select_node()...
})
.bind("move_node.jstree", function(event, data) {
var item = data.rslt.o;
var parent = data.rslt.np;
var previous = null;
var next = null;
switch(data.rslt.p) {
case "before":
next = data.rslt.o.next();
previous = data.rslt.o.prev();
break;
case "after" :
previous = data.rslt.o.prev()
next = data.rslt.o.next();
break;
case "inside":
case "first" :
case "last":
break;
default:
alert("position not handled: " + data.rslt.p + " " + data.rslt.r.attr("id"));
return;
}
var params = {
id: item.attr('data-page-id'),
parent_id: parent ? parent.attr('data-page-id') : undefined,
prev_id: previous ? previous.attr('data-page-id') : undefined,
next_id: next ? next.attr('data-page-id') : undefined
};
$.humpyard.tokenized_post(treeview.attr('data-sortable-update-url'), params);
})
.jstree({
"core" : {
"html_titles": true,
"animation": 100
},
"dnd" : {
//"drop_target" : true,
//"drag_target" : true,
"drop_finish" : function(data) {
// console.log("drop_finish");
// console.log(data);
},
"drag_check" : function (data) {
// check root node - no dnd
// console.log("DRAGCHECK");
return {
after : true,
before : true,
inside : true
};
},
"drag_finish" : function () {
alert("DRAG OK");
}
},
"themes" : {
"theme" : "default",
"dots" : true,
"icons" : true,
"url": "/stylesheets/jstree/style.css"
},
"ui" : {
"select_limit": 1
},
"plugins" : [
"themes",
"html_data",
"crrm",
"dnd",
"ui"
]
});
},
submitForm: function(form, dialog, targetForm) {
if(typeof(targetForm) == 'undefined') {
targetForm = form
}
var options = {
dataType: 'json',
complete: function(xhr, status) {
result = jQuery.parseJSON(xhr.responseText);
// reset error messages
$('.field-highlight', form).removeClass("ui-state-error");
$('.field-errors', form).empty().hide();
// execute commands given by ajax call
$.each(result, function(attr, options) {
if($.humpyard.ajax_dialog_commands[attr]) {
$.humpyard.ajax_dialog_commands[attr](dialog, targetForm, options);
}
});
}
}
if(form.find('input[type=file]').length > 0 || form.attr("enctype") == "multipart/form-data") {
options['data'] = { ul_quirk: 'true' };
options['iframe'] = true
}
if(form.trigger('humpyard:form:submit')) {
form.ajaxSubmit(options);
}
},
dialogLink: function(link, dialog) {
var url = '' + link.attr('href');
var options = {
url: url,
dataType: 'json',
complete: function(xhr, status) {
result = jQuery.parseJSON(xhr.responseText);
// execute commands given by ajax call
$.each(result, function(attr, options) {
if($.humpyard.ajax_dialog_commands[attr]) {
$.humpyard.ajax_dialog_commands[attr](dialog, null, options);
}
});
}
};
if(link.trigger('humpyard:link:click')) {
$.ajax(options);
}
},
dialog: function(url, options) {
options = options || {};
var post_options = options['post'] || null;
var get_options = $.param(options['get'] || {});
var dialog_id = options['dialog_id'];
var dialog = null;
options['close'] = options['close'] || function(ev, ui) { $(this).remove(); };
// Remove get and post from options for dialog
/*
if(options['get']) {
options.splice('get');
}
if(options['post']) {
options.splice('post');
}
*/
options['get'] = null;
options['post'] = null;
options['dialog_id'] = null;
if(dialog_id) {
if($('#' + dialog_id).size()) {
dialog = $('#' + dialog_id);
dialog.dialog("moveToTop");
return;
} else {
dialog = $('').appendTo('body').dialog(options);
}
} else {
dialog = $('').appendTo('body').dialog(options);
}
dialog.load(url+(get_options ? '?'+get_options : ''), post_options, function(response, status, xhr) {
if (status == "error") {
var error_content = 'Sorry, an error occurred: '+xhr.statusText+' ['+xhr.status+']
';
dialog.dialog({
title: 'An Error occured',
dialogClass: 'alert',
buttons: {
'Ok': function() {
$(this).dialog('close');
}
}
});
dialog.html(error_content);
} else {
dialog.dialog({
title: $('.humpyard-dialog-title', dialog).html()
});
$('.humpyard-dialog-title', dialog).remove();
$.humpyard.initForm(dialog);
$.humpyard.initPages(dialog);
$.humpyard.initTabView(dialog);
$.humpyard.initTreeView(dialog);
$.humpyard.initEditButtons($('.humpyard-form-buttons a, .humpyard-form-buttons button', dialog));
// Add buttons
buttons = {};
if($('form[data-dialog-form]:first', $(this)).size()) {
buttons = {};
buttons['Ok'] = function() {
var form = $('form[data-dialog-form]:first', $(this));
$.humpyard.submitForm(form, dialog);
};
buttons['Cancel'] = function() {
$(this).dialog('close');
}
} else {
buttons = false;
}
$('.humpyard-dialog-buttons').each(function(i,k){
dialog.dialog({
buttons: buttons
});
});
$('.humpyard-dialog-buttons').remove();
// run optional dialog functionality
if(options['load']) {
options['load'](dialog);
}
$.humpyard.dialog_count++;
}
});
},
endOfClass: true
}
})(jQuery);
// Humpyard actions / UJS
jQuery(function($) {
var csrf_token = $('meta[name=csrf-token]').attr('content'),
csrf_param = $('meta[name=csrf-param]').attr('content');
// bind ajax indicator to ajax events
$(document).ajaxSend(function() {
$(".ajax-indicator").addClass("active");
}).ajaxStop(function() {
$(".ajax-indicator").removeClass("active");
});
// Dialog UJS
$('a[data-dialog]').live('click', function (e) {
var options = {};
var url = $(this).attr('href');
$.each($(this).attr('data-dialog').split(';'), function(i){
attr = this.split(':');
switch(attr[0]) {
case 'modal':
case 'dialog_id':
options[attr[0]] = attr[1];
break;
case 'size':
size = attr[1].split('x');
options['width'] = parseInt(size[0]);
if(size[1]) {
options['height'] = parseInt(size[1]);
}
break;
}
})
$.humpyard.dialog(url, options);
e.preventDefault();
});
// Init Humpyard UI
$.humpyard.initEditButtons($('#hy-top a'));
$.humpyard.initElements($('#hy-body'));
// copied and modified the start, stop and drag from ui.draggable to this call
$('div[data-addable]').draggable({
helper: 'clone',
revert: 'invalid',
start: function(event, ui) {
var inst = $(this).data("draggable"), uiSortable = $.extend({}, ui, { item: inst.element });
inst.sortables = [];
$('div[data-droppable=' + $(this).attr('data-draggable') + ']').each(function() {
var sortable = $.data(this, 'sortable');
if (sortable && !sortable.options.disabled) {
inst.sortables.push({
instance: sortable,
shouldRevert: sortable.options.revert
});
sortable._refreshItems(); //Do a one-time refresh at start to refresh the containerCache
sortable._trigger("activate", event, uiSortable);
}
});
},
stop: function(event, ui) {
//If we are still over the sortable, we fake the stop event of the sortable, but also remove helper
var inst = $(this).data("draggable"),
uiSortable = $.extend({}, ui, { item: inst.element });
$.each(inst.sortables, function() {
if(this.instance.isOver) {
this.instance.isOver = 0;
inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance
this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work)
//The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: 'valid/invalid'
if(this.shouldRevert) this.instance.options.revert = true;
//Trigger the stop of the sortable
this.instance._mouseStop(event);
this.instance.options.helper = this.instance.options._helper;
//If the helper has been the original item, restore properties in the sortable
if(inst.options.helper == 'original')
this.instance.currentItem.css({ top: 'auto', left: 'auto' });
} else {
this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance
this.instance._trigger("deactivate", event, uiSortable);
}
});
},
drag: function(event, ui) {
var inst = $(this).data("draggable"), self = this;
var checkPos = function(o) {
var dyClick = this.offset.click.top, dxClick = this.offset.click.left;
var helperTop = this.positionAbs.top, helperLeft = this.positionAbs.left;
var itemHeight = o.height, itemWidth = o.width;
var itemTop = o.top, itemLeft = o.left;
return $.ui.isOver(helperTop + dyClick, helperLeft + dxClick, itemTop, itemLeft, itemHeight, itemWidth);
};
var dragIn = function(draggable) {
//If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once
if(!draggable.instance.isOver) {
draggable.instance.isOver = 1;
//Now we fake the start of dragging for the sortable instance,
//by cloning the list group item, appending it to the sortable and using it as inst.currentItem
//We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one)
draggable.instance.currentItem = $(self).clone().appendTo(draggable.instance.element).data("sortable-item", true);
draggable.instance.options._helper = draggable.instance.options.helper; //Store helper option to later restore it
draggable.instance.options.helper = function() { return ui.helper[0]; };
event.target = draggable.instance.currentItem[0];
draggable.instance._mouseCapture(event, true);
draggable.instance._mouseStart(event, true, true);
//Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes
draggable.instance.offset.click.top = inst.offset.click.top;
draggable.instance.offset.click.left = inst.offset.click.left;
draggable.instance.offset.parent.left -= inst.offset.parent.left - draggable.instance.offset.parent.left;
draggable.instance.offset.parent.top -= inst.offset.parent.top - draggable.instance.offset.parent.top;
inst._trigger("toSortable", event);
inst.dropped = draggable.instance.element; //draggable revert needs that
//hack so receive/update callbacks work (mostly)
inst.currentItem = inst.element;
draggable.instance.fromOutside = inst;
}
//Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable
if(draggable.instance.currentItem) draggable.instance._mouseDrag(event);
}
var dragOut = function(draggable) {
//If it doesn't intersect with the sortable, and it intersected before,
//we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval
if(draggable.instance.isOver) {
draggable.instance.isOver = 0;
draggable.instance.cancelHelperRemoval = true;
//Prevent reverting on draggable forced stop
draggable.instance.options.revert = false;
// The out event needs to be triggered independently
draggable.instance._trigger('out', event, draggable.instance._uiHash(draggable.instance));
draggable.instance._mouseStop(event, true);
draggable.instance.options.helper = draggable.instance.options._helper;
//Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size
draggable.instance.currentItem.remove();
if(draggable.instance.placeholder) draggable.instance.placeholder.remove();
inst._trigger("fromSortable", event);
inst.dropped = false; //draggable revert needs that
}
}
var intersections = [];
$.each(inst.sortables, function(i) {
// console.log(this);
//Copy over some variables to allow calling the sortable's native _intersectsWith
this.instance.positionAbs = inst.positionAbs;
this.instance.helperProportions = inst.helperProportions;
this.instance.offset.click = inst.offset.click;
// Collect all intersections
if(this.instance._intersectsWith(this.instance.containerCache)) {
intersections.push(this.instance);
};
});
// Find top most intersection
var topIntersection = intersections.pop();
while(actual = intersections.pop()) {
if($.inArray(actual.element, $('div[data-droppable]', topIntersection.element))) {
topIntersection = actual;
}
}
// Handle drag in and out of intersections
$.each(inst.sortables, function(i) {
if(this.instance == topIntersection) {
// console.log('drag in');
dragIn(this);
} else {
// console.log('drag out');
dragOut(this);
}
});
}
});
/*
// Simple Method not working with nested elements
$('div[data-addable]').draggable({
connectToSortable: 'div[data-droppable]',
helper: 'clone',
revert: 'invalid'
});
*/
// Humpyard elements menu
$('.hy-el').live('mouseover', function(){
var el = $(this);
$('.hy-el').removeClass('hy-el-active');
el.addClass('hy-el-active');
$('.hy-el-menu', el).position({
my: 'left top',
at: 'left top',
of: el,
offset: "2 2"
});
$('.hy-marker-frame.top', el).position({ my: 'left top', at: 'left top', of: el }).width(el.width()).height(1);
$('.hy-marker-frame.bottom', el).position({ my: 'left bottom', at: 'left bottom', of: el }).width(el.width()).height(1);
$('.hy-marker-frame.left', el).position({ my: 'left top', at: 'left top', of: el }).width(1).height(el.height());
$('.hy-marker-frame.right', el).position({ my: 'right top', at: 'right top', of: el }).width(1).height(el.height());
}).live('mouseout', function(){
$('.hy-el').removeClass('hy-el-active');
});
$('a[data-draghandle]').live('click',function(e){
e.preventDefault();
});
// dialog left column links
$('div[data-dialog-link] a, a[data-dialog-link]').live('click', function(e){
var columns = $(this).parents('.dialog-columns:first');
var content = columns.children('.right-dialog-column');
$('a', columns).removeClass('active');
$(this).addClass('active');
content.empty().load($(this).attr('href'), function(response, status, xhr) {
dialog = columns.parents('.ui-dialog-content:first');
if (status == "error") {
var error_content = 'Sorry, an error occurred: '+xhr.statusText+' ['+xhr.status+']
';
dialog.dialog({
title: 'An Error occured',
dialogClass: 'alert',
buttons: {
'Ok': function() {
$(this).dialog('close');
}
}
});
dialog.html(error_content);
} else {
dialog.dialog({
title: $('.humpyard-dialog-title', content).html()
});
$('.humpyard-dialog-title', content).remove();
$.humpyard.initForm(content);
$.humpyard.initTabView(content);
$.humpyard.initEditButtons($('.humpyard-form-buttons a, .humpyard-form-buttons button', content));
}
});
e.preventDefault();
});
// Links to commands UJS
commands = {
toggleEditMode: function(link) {
$('.hy-eb').toggleClass('hy-edit-active', 250);
$('.hy-e').toggleClass('hy-edit-active', 250);
},
replaceElement: function(link) {
}
}
$('form[data-dialog-remote]').live('submit', function(e) {
$.humpyard.submitForm($(this), $(this).parents('.ui-dialog-content:first'));
e.preventDefault();
});
$('div[data-dialog-remote]:not([data-remote]) a, a[data-dialog-remote]:not([data-remote])').live('click', function(e) {
$.humpyard.dialogLink($(this), $(this).parents('.ui-dialog-content:first'));
e.preventDefault();
});
$('a[data-command],input[data-command]').live('click', function (e) {
commands[$(this).attr('data-command')]($(this));
e.preventDefault();
});
$('a[data-dialog-method]').live('click', function(e) {
var link = $(this),
href = link.attr('href'),
method = link.attr('data-dialog-method'),
form = $('