Separate out ActionTabSet functionality into a new file & clean up.

This commit is contained in:
Naomi Guyer 2012-12-05 16:07:07 +13:00 committed by Ingo Schommer
parent ee797e4a48
commit 5cef05ebea
5 changed files with 225 additions and 238 deletions

View File

@ -296,6 +296,7 @@ class LeftAndMain extends Controller implements PermissionProvider {
array(
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Layout.js',
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.js',
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.ActionTabSet.js',
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js',
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js',
FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js',

View File

@ -0,0 +1,222 @@
/**
* File: LeftAndMain.ActionTabset.js
*
* Contains rules for .ss-ui-action-tabset, used for:
* * Site tree action tabs (to perform actions on the site tree)
* * Actions menu (Edit page actions)
*
*/
(function($){
$.entwine('ss', function($) {
/**
* Generic rules for all ss-ui-action-tabsets
* * ActionMenus
* * SiteTree ActionTabs
*/
$('.ss-tabset.ss-ui-action-tabset').entwine({
onadd: function() {
// Make sure the .ss-tabset is already initialised to apply our modifications on top.
this._super();
//Set actionTabs to allow closing and be closed by default
this.tabs({'collapsible': true, 'active': false});
},
/**
* Deal with available vertical space
*/
'ontabsbeforeactivate': function(event, ui) {
this.riseUp(event, ui);
},
/**
* Handle opening and closing tabs
*/
onclick: function(event, ui) {
this.attachCloseHandler(event, ui);
},
/**
* Generic function to close open tabs. Stores event in a handler,
* and removes the bound event once activated.
*
* Note: Should be called by a click event attached to 'this'
*/
attachCloseHandler: function(event, ui) {
var that = this, frame = $('.cms').find('iframe'), closeHandler;
// Create a handler for the click event so we can close tabs
// and easily remove the event once done
closeHandler = function(event) {
var panel, frame;
panel = $(event.target).closest('.ss-ui-action-tabset .ui-tabs-panel');
// If anything except the ui-nav button is clicked,
// close panel and remove handler
if (!$(event.target).closest(that).length || $(panel).length) {
that.tabs('option', 'active', false); // close tabs
// remove click event from objects it is bound to (iframe's and document)
frame = $('.cms').find('iframe');
frame.each(function(index, iframe){
$(iframe).contents().off('click', closeHandler);
});
$(document).off('click', closeHandler);
}
};
// Bind click event to document, and use closeHandler to handle the event
$(document).on('click', closeHandler);
// Make sure iframe click also closes tab
// iframe needs a special case, else the click event will not register here
if(frame.length > 0){
frame.each(function(index, iframe) {
$(iframe).contents().on('click', closeHandler);
});
}
},
/**
* Function riseUp checks to see if a tab should be opened upwards
* (based on space concerns). If true, the rise-up class is applied
* and a new position is calculated and applied to the element.
*
* Note: Should be called by a tabsbeforeactivate event
*/
riseUp: function(event, ui) {
var elHeight, trigger, endOfWindow, elPos, activePanel, activeTab, topPosition, containerSouth, padding;
// Get the numbers needed to calculate positions
elHeight = $(this).find('.ui-tabs-panel').outerHeight();
trigger = $(this).find('.ui-tabs-nav').outerHeight();
endOfWindow = ($(window).height() + $(document).scrollTop()) - trigger;
elPos = $(this).find('.ui-tabs-nav').offset().top;
activePanel = ui.newPanel;
activeTab = ui.newTab;
if (elPos + elHeight >= endOfWindow && elPos - elHeight > 0){
this.addClass('rise-up');
if (activeTab.position() !== null){
topPosition = -activePanel.outerHeight();
containerSouth = activePanel.parents('.south');
if (containerSouth){
// If container is the southern panel, make tab appear from the top of the container
padding = activeTab.offset().top - containerSouth.offset().top;
topPosition = topPosition-padding;
}
$(activePanel).css('top',topPosition+"px");
}
} else {
// else remove the rise-up class and set top to 0
this.removeClass('rise-up');
if (activeTab.position() !== null){
$(activePanel).css('top','0px');
}
}
return false;
}
});
/**
* ActionMenus
* * Specific rules for ActionMenus, used for edit page actions
*/
$('.cms-content-actions .ss-tabset.ss-ui-action-tabset').entwine({
/**
* Make necessary adjustments before tab is activated
*/
'ontabsbeforeactivate': function(event, ui) {
this._super(event, ui);
//Set the position of the opening tab (if it exists)
if($(ui.newPanel).length > 0){
$(ui.newPanel).css('left', ui.newTab.position().left+"px");
}
}
});
/**
* SiteTree ActionTabs
* Specific rules for site tree action tabs. Applies to tabs
* within the expanded content area, and within the sidebar
*/
$('.cms-actions-row.ss-tabset.ss-ui-action-tabset').entwine({
/**
* Make necessary adjustments before tab is activated
*/
'ontabsbeforeactivate': function(event, ui) {
this._super(event, ui);
// Remove tabset open classes (Last gets a unique class
// in the bigger sitetree. Remove this if we have it)
$(this).closest('.ss-ui-action-tabset')
.removeClass('tabset-open tabset-open-last');
}
});
/**
* SiteTree ActionTabs: expanded
* * Specific rules for siteTree actions within the expanded content area.
*/
$('.cms-content-fields .ss-tabset.ss-ui-action-tabset').entwine({
/**
* Make necessary adjustments before tab is activated
*/
'ontabsbeforeactivate': function(event, ui) {
this._super(event, ui);
if($( ui.newPanel).length > 0){
if($(ui.newTab).hasClass("last")){
// Align open tab to the right (because opened tab is last)
$(ui.newPanel).css({'left': 'auto', 'right': '0px'});
// Last needs to be styled differently when open, so apply a unique class
$(ui.newPanel).parent().addClass('tabset-open-last');
}else{
// Assign position to tabpanel based on position of relivent active tab item
$(ui.newPanel).css('left', ui.newTab.position().left+"px");
// If this is the first tab, make sure the position doesn't include border
// (hard set position to 0 ), and add the tab-set open class
if($(ui.newTab).hasClass("first")){
$(ui.newPanel).css('left',"0px");
$(ui.newPanel).parent().addClass('tabset-open');
}
}
}
}
});
/**
* SiteTree ActionTabs: sidebar
* * Specific rules for when the site tree actions panel appears in
* * the side-bar
*/
$('.cms-tree-view-sidebar .cms-actions-row.ss-tabset.ss-ui-action-tabset').entwine({
// If actions panel is within the sidebar, apply active class
// to help animate open/close on hover
'from .ui-tabs-nav li': {
onhover: function(e) {
$(e.target).parent().find('li .active').removeClass('active');
$(e.target).find('a').addClass('active');
}
},
/**
* Make necessary adjustments before tab is activated
*/
'ontabsbeforeactivate': function(event, ui) {
this._super(event, ui);
// Reset position of tabs, else anyone going between the large
// and the small sitetree will see broken tabs
// Apply styles with .css, to avoid overriding currently applied styles
$(ui.newPanel).css({'left': 'auto', 'right': 'auto'});
if($(ui.newPanel).length > 0){
$(ui.newPanel).parent().addClass('tabset-open');
}
}
});
});
}(jQuery));

View File

@ -572,7 +572,7 @@ jQuery.noConflict();
if(typeof(window.sessionStorage)=="undefined" || window.sessionStorage == null) return;
var selectedTabs = [], url = this._tabStateUrl();
this.find('.cms-tabset,.ss-tabset').each(function(i, el) {
this.find('.cms-tabset,.ss-tabset').each(function(i, el) {
var id = $(el).attr('id');
if(!id) return; // we need a unique reference
if(!$(el).data('tabs')) return; // don't act on uninit'ed controls

View File

@ -812,4 +812,3 @@ fieldset.switch-states{
}
//old web-kit browser fix
@-webkit-keyframes bugfix { from { position: relative; } to { position: relative; } }

View File

@ -2,19 +2,8 @@
$.entwine('ss', function($){
/**
* Lightweight wrapper around jQuery UI tabs for generic tab set-up
* and special rules for two other use cases (ss-ui-action-tabset):
* * Site tree action tabs (to perform actions on the site tree)
* * Actions menu (Edit page actions)
*/
$('.ss-tabset').entwine({
/******************************************************
* Lightweight wrapper around jQuery UI tabs:
* * onadd
* * onremove
* * redrawTabs
* * rewriteHashlinks
*******************************************************/
onadd: function() {
// Can't name redraw() as it clashes with other CMS entwine classes
this.redrawTabs();
@ -27,11 +16,6 @@
redrawTabs: function() {
this.rewriteHashlinks();
this.tabs();
//Apply special behaviour to ss-ui-action-tabset
if(this.hasClass('ss-ui-action-tabset')){
this.actionTabs();
}
},
/**
@ -46,226 +30,7 @@
if(!matches) return;
$(this).attr('href', document.location.href.replace(/#.*/, '') + matches[0]);
});
},
/***************************************************
* Custom functionality for special action tabsets
* * actionTabs
* * siteTreeActions
* * actionsMenu
* * closeTabs
* * riseUp
***************************************************/
/*
Apply generic rules for action tabs (collapsible, rise, and close),
then call specific functions to handle each type of action tab
*/
actionTabs: function(){
var that = this;
//Set actionTabs to allow closing and be closed by default
this.tabs(
'option',
'collapsible',
true
).tabs('option', 'active', false);
//Call close function on beforeactivate event
this.on( "tabsbeforeactivate", function(event, ui) {
that.closeTabs(event, ui);
});
// Call riseUp funciton on befporeactivate to check if tabs should
// open upwards (based on available space) and adjust
this.on( "tabsbeforeactivate", function(event, ui) {
that.riseUp(event, ui);
});
// Apply special behaviour depending on whether tabs are
// sitetree actions, or an actionmenu
if(this.parents('.cms-content-actions')){
this.actionsMenu();
} else if(this.hasClass('cms-actions-row')){
this.siteTreeActions();
}
},
/*
* Apply custom rules to the Actions Menu
* Currently includes positioning logic
*/
actionsMenu: function(){
this.tabs({
beforeActivate:function(event, ui){ //Set options before tab activated (but after clicked)
var activePanel = ui.newPanel; //panel about to open
var activeTab = ui.newTab; //tab nav item about to become active
//Set the position of the opening tab (if it exists)
if($(activePanel).length > 0){
$(activePanel).css('left', activeTab.position().left+"px");
}
}
});
},
/*
Apply rules to the siteTree actions. These action panels should
recieve different positions and classes depending on whether they are
appearing in the full page site tree view, or in the sidebar
*/
siteTreeActions: function(){
var that = this;
var container = this.parent().parent();
//Remove open classes on beforeactivate
this.on( "tabsbeforeactivate", function(event, ui) {
// Remove tabset open classes (last gets a unique class
// in the bigger sitetree, so remove this too)
$(that).closest('.ss-ui-action-tabset')
.removeClass('tabset-open')
.removeClass('tabset-open-last');
});
/* Apply specific rules if the actions panel appears in the side-bar
* Includes:
* * a hover helper class for animation,
* * reseting positioning of panels
*/
if($(container).hasClass('cms-tree-view-sidebar')){
/* If actions panel is within the sidebar, apply active class
to help animate open/close on hover */
$('.ui-tabs-nav li').hover(function(){
$(this).parent().find('li .active').removeClass('active');
$(this).find('a').addClass('active');
});
/* Reset position of tabs, else anyone going between the large
and the small sitetree will see broken tabs */
this.tabs({
// Note: beforeActivate runs when a tab is clicked,
// but before it is visible.
beforeActivate:function(event, ui){
var activePanel = ui.newPanel; //the new active panel
//Apply styles with css, to avoid overriding currently applied styles
$(activePanel).css({'left': 'auto', 'right': 'auto'}); //reset left and right positioning
if($(activePanel).length > 0){
$(activePanel).parent().addClass('tabset-open');
}
}
});
}else{
/* If the tabs are in the full site tree view, do some
positioning so tabPanel stays with relevent tab */
this.tabs({
beforeActivate:function(event, ui){
var activePanel = ui.newPanel;
var activeTab = ui.newTab;
if($(activePanel).length > 0){
if($(activeTab).hasClass("last")){
// Align open tab to the right (because opened tab is last)
$(activePanel).css({'left': 'auto', 'right': '0px'});
//last needs to be styled differently when open, so apply a unique class
$(activePanel).parent().addClass('tabset-open-last');
}else{
//Assign position to tabpanel based on position of relivent activeTab item
$(activePanel).css('left', activeTab.position().left+"px");
// If this is the first tab, make sure the position doesn't include border
// (hard set position to 0 ), and add the tab-set open class
if($(activeTab).hasClass("first")){
$(activePanel).css('left',"0px");
$(activePanel).parent().addClass('tabset-open');
}
}
}
}
});
}
},
/*
* Generic function to close open tabs when something other than
* the open tab is clicked. Stores event in a handler, and removes
* the bound event once activated. Used by ss-ui-action-tabset.
*
* Note: Should be called by a tabsbeforeactivate event
*/
closeTabs: function(event, ui){
var that = this;
var frame = $('.cms').find('iframe'); //get all iframes on the page
// Create a handler for the click event so we can close tabs
// and easily remove the event once done
var closeHandler = function(event){
//close open tab
if (!$(event.target).closest(that).length) {
that.tabs('option', 'active', false); // close tabs
//remove click event from objects it is bound to (iframe's and document)
var frame = $('.cms').find('iframe');
frame.each(function(index, iframe){
$(iframe).contents().off('click', closeHandler);
});
$(document).off('click', closeHandler);
};
}
//Bind click event to document, and use closeHandler to handle the event
$(document).on('click', closeHandler);
// Make sure iframe click also closes tab
// iframe needs a special case, else the click event will not register here
if(frame.length > 0){
frame.each(function(index, iframe){
$(iframe).contents().on('click', closeHandler);
});
}
},
/*****************************************************************
* Function riseUp checks to see if a tab should be opened upwards
* (based on space concerns). If true, the rise-up class is applied
* and a new position is calculated and applied to the element.
*
* Note: Should be called by a tabsbeforeactivate event
******************************************************************/
riseUp: function(event, ui){
// Get the numbers needed to calculate positions
var elHeight = $(this).find('.ui-tabs-panel').outerHeight();
var trigger = $(this).find('.ui-tabs-nav').outerHeight();
var endOfWindow = ($(window).height() + $(document).scrollTop()) - trigger;
var elPos = $(this).find('.ui-tabs-nav').offset().top;
var activePanel = ui.newPanel;
var activeTab = ui.newTab;
if (elPos + elHeight >= endOfWindow && elPos - elHeight > 0){
this.addClass('rise-up');
if (activeTab.position() != null){
var topPosition = -activePanel.outerHeight();
var containerSouth = activePanel.parents('.south');
if (containerSouth){
//If container is the southern panel, make tab appear from the top of the container
var padding = activeTab.offset().top - containerSouth.offset().top;
topPosition = topPosition-padding;
}
$(activePanel).css('top',topPosition+"px");
}
} else {
//else remove the rise-up class and set top to 0
this.removeClass('rise-up');
if (activeTab.position() != null){
$(activePanel).css('top','0px');
}
}
return false;
}
}
});
});
})(jQuery);