// $Id: float_window.src.js,v 1.1 2008/12/05 15:40:11 skilip Exp $ /** * floatWin(options) * * @description: Adds a floating window to body * * @to do: - Fix the maximal height of the floating window in IE * - Add a fixed top and left position on init. And a save last position option * * @return Object Returns a floafing window object. * @param Object options All options to pass to the window on init * * window_id String the id prefix for the window, * window_class String the class prefix for the window, * resizable Boolean whether the window can be maximized or not, * show Boolean Whether the window must be shown on init, * add_close_button Boolean Whether the window must have a close button (default: true), * draggable Boolean Whether the window is draggable (default: true), * show_button String A jQuery selector for the element which shows the window after an onclick event * onload_callback String A callback script triggered after the window has loaded * min_width String || Number The minimal width of the window. e.a.: 10, '10px' or '10%'. If the content is wider, this value will be overwritten by the contents width * min_height String || Number The minimal height of the window. e.a.: 10, '10px' or '10%'. If the content is higher, this value will be overwritten by the contents height * */ function floatWin(options) { var fw = this; fw.options = (options) || {}; // Configuration variables fw.window_id = 'float_window'; fw.window_class = 'float_window'; fw.resizable = true; fw.add_close_button = true; fw.draggable = true; fw.show = true; fw.show_button = false; fw.onload_callback = false; fw.ajax_success_callback = false; fw.min_width = 300; fw.min_height = 80; fw.margin = {top:6, bottom:14, left:14, right:14}; // Other variables fw.content_properties = {}; fw.float_win_dimensions = {}; fw.window_visible = false; fw.maximized = false; fw.reload_content_after_messages = true; fw.new_content_loaded = false; fw.form_disabled = true; fw.close = false; fw.window_obj; fw.window_obj; fw.window_title_obj; fw.redirect; fw.dragged; fw.clicked_url; /** * Initializes the floating window */ fw.init = function() { //trace(fw.options); fw.setConfigurationOptions(); fw.placeWindow(); // We need a timeout because the some browser can scroll down after the page is loaded. // If we omit a timeout, sometimes the floating window is not properly aligned. if(fw.show) setTimeout(function() { eval('window.float_windows.' + fw.window_id + '.showWindow();'); }, 300); setTimeout(function() { eval('window.float_windows.' + fw.window_id + '.onLoadHandler();'); }, 300); fw.addEventListeners(true); }; /** * This function checks for all passed arguments in the options object. * If a configuration option is given, the default values is overwritten. */ fw.setConfigurationOptions = function() { // Here we check wheter a required setting is set in the arguments options. If not, we'll set the default value for(var option in fw.options) if(fw.options[option] !== undefined && fw.options[option] !== '') fw[option] = fw.options[option]; }; /** * Places an instance of a floating window in the body */ fw.placeWindow = function() { // First check if the window is not placed already if($("body").find("#" + fw.window_id).size() > 0) return; var window_html = ''; window_html += '
'; fw.window_obj = $(window_html).appendTo('body'); fw.window_title_obj = fw.window_obj.find("#" + fw.window_id + '_title'); fw.window_content_obj = fw.window_obj.find("#" + fw.window_id + '_content_container'); if(fw.add_close_button) fw.close_button_obj = $('').appendTo('#' + fw.window_id + ' .' + fw.window_class + '_title_container'); if(fw.resizable) fw.resizable_button_obj = $('').appendTo('#' + fw.window_id + ' .' + fw.window_class + '_title_container'); fw.left_td_width = parseInt(fw.window_obj.find('tr:eq(0) td:eq(0)').css('width')); fw.right_td_width = parseInt(fw.window_obj.find('tr:eq(0) td:eq(2)').css('width')); var temp1 = 'td:not(#' + fw.window_id + '_middle_center_td)'; var temp2 = fw.window_obj.find('td:not(#' + fw.window_id + '_middle_center_td)'); if(temp2) fw.window_obj.find('td:not(#' + fw.window_id + '_middle_center_td)').cssPNGFix(); }; /** * Trigger a callback script after the window is placed in the DOM. */ fw.onLoadHandler = function() { if(fw.onload_callback) eval(fw.onload_callback); }; /** * Trigger a callback script after the content is placed after an AJAX response */ fw.onAJAXLoadHandler = function() { if(fw.ajax_success_callback) eval(fw.ajax_success_callback); }; /** * Sets the content for the floating window */ fw.setContent = function() { fw.new_content_loaded = false; // If there's a drupal function given, we'll get the content by an AJAX request if(fw.content_properties.ajax_params) { if(!fw.ajax_done) { fw.getAJAXContent(); return; }; fw.ajax_done = false; }; fw.stopLoading(); if(fw.reload_content_after_messages) { fw.window_title_obj.html(fw.content_properties.title); fw.window_content_obj.html(fw.content_properties.content); fw.new_content_loaded = true; }; // reset reload_content_after_messages fw.reload_content_after_messages = true; if(!fw.dragged) fw.align(); // Only align if the window has not been dragged fw.window_obj.css({'visibility':'visible'}); fw.onAJAXLoadHandler(); // Add event listeners to the AJAX loaded content if(fw.content_properties.ajax_params) fw.contentAddEventListeners(); }; /** * Gets the content for the floating window by an AJAX request */ fw.getAJAXContent = function() { fw.content_properties.ajax_params.clicked_url = fw.clicked_url; $.ajax({ url:Drupal.settings.float_window_ajax_response_path, data:fw.content_properties.ajax_params, dataType:'json', type:'POST', success:function(json) { if(json.content) fw.content_properties.content = json.content; if(json.title) fw.content_properties.title = json.title; if(json.height) fw.min_height = json.height; if(json.width) fw.min_width = json.width; if(json.messages) fw.handleResponseMessages(json.messages, json.redirect); if(json.ajax_success_callback) fw.ajax_success_callback = json.ajax_success_callback; if(!json.messages && !json.content && json.redirect && fw.reload_content_after_messages) { fw.redirect(json.redirect); }; // If a submit function has set $form_state['close_float_window'] to TRUE, // the window will be closed and reinitialized. if(json.close) { fw.hideWindow(true); } else { fw.window_content_obj.find('.form-submit').removeAttr('disabled'); fw.form_disabled = false; fw.ajax_done = true; fw.setContent(); }; } }); }; /** * Add event listeners to the AJAX loaded content */ fw.contentAddEventListeners = function() { if(fw.new_content_loaded) { fw.window_content_obj.find('.form-submit').not('[float_window_content_func]').click(function() { // Avoid multiple submits before the AJAX request gets it's response $(this).attr('disabled', 'disabled'); fw.form_disabled = true; // To avoid a submit when the user clicks ENTER after selecting a result of an autocomplete list, // we'll just check weither the autocomplete div exists or not. if ($('#autocomplete').size() == 0) { fw.contentFormSubmit($(this).val()); } return false; }); }; // Here we look for elements with the attribute float_window_content_func. // If the element is clicked, the form of the value of float_window_content_func replaces the current content fw.window_content_obj.find('[float_window_content_func]').click(function() { var form_args = {float_window_content_func:$(this).attr('float_window_content_func')}; if(fw.content_properties.ajax_params.is_form) form_args.is_form = true; fw.content_properties.ajax_params = form_args; fw.dragged = false; fw.startLoading(); fw.setContent(); return false; }); if(window.floatwin_show_buttons) { $.each(window.floatwin_show_buttons, function(winid, selector) { fw.window_obj.find(selector).click(function() { window.float_windows[winid].showWindow(); return false; }); }); }; fw.window_content_obj.find('.form-text.error').keyup(function() { if($(this).val() !== '') { $(this).removeClass('error'); $(this).unbind('keyup'); }; }); if(fw.window_content_obj.find('input[@type=file]').size() > 0) { // If the ajaxFileUpload is not insitialized, create an instance first if(!Drupal.ajax_file_upload) { Drupal.ajax_file_upload = new ajaxUpload(); } else { if(fw.new_content_loaded) { Drupal.ajax_file_upload.init(); }; }; }; Drupal.behaviors.collapse(); }; /** * Displays drupal messages and/or errors returned by an AJAX request */ fw.handleResponseMessages = function(messages, redirect) { fw.reload_content_after_messages = (!messages.form && !messages.error); var may_redirect = (fw.reload_content_after_messages && redirect); if(Drupal.inline_dialog) { if(messages.form) { if(!messages.error) messages.error = []; Drupal.inline_dialog.wrong_fields = []; for(var key in messages.form) { // Add the form error to the inline_dialog wrong fields array Drupal.inline_dialog.wrong_fields.push('edit-' + key); // Store the form error in the errors array messages.error.push(messages.form[key]); }; delete(messages.form); }; Drupal.settings.messages = messages; Drupal.inline_dialog.drupalMessages(); } else { for(var type in messages) { var result = ''; for(var key in messages[type]) result += messages[type][key] + "\n"; alert(result); }; }; if(may_redirect) fw.redirect(redirect, (Drupal.inline_dialog)); }; /** * If the form has set a #redirect, we will do this using javascript */ fw.redirect = function(direction, use_inline_dialog) { if(use_inline_dialog) { Drupal.inline_dialog.redirect = direction; } else { window.location = direction; }; }; /** * Handle the form submition. This will be don by an AJAX request, instead of having a page refresh */ fw.contentFormSubmit = function(op) { // trace('contentFormSubmit'); // Store all form values in an object, so we can pass it as ajax parameters var form_args = { float_window_content_func:fw.window_content_obj.find('input[@name=form_id]').attr('value'), is_form:fw.content_properties.ajax_params.is_form }; var form_elements = ['input', 'textarea', 'select']; // lets loop through all valid form elements and store it in form_values // We'll pass it to the AJAX function as arguments so Drupal will get the form values for(var i = 0; i < form_elements.length; i++) { fw.window_content_obj.find(form_elements[i]).each(function() { if($(this).attr('type') == 'checkbox') { form_args[$(this).attr('name')] = ($(this).attr('checked')) ? $(this).val() : 0; } else { form_args[$(this).attr('name')] = ($(this).val()) || ''; }; }); }; // Set the submittion operation form_args['op'] = op; // If we need to use the fileupload from the ajax_file_upload module, initialize the processFormFiles function // if(Drupal.ajax_file_upload) Drupal.ajax_file_upload.processFormFiles(); fw.content_properties.ajax_params = form_args; fw.setContent(); // Fixes a bug in firefox $('input:text').attr({'autocomplete':'off'}).blur(); // In order to let user_register_validate() validate the name, we need to add '/register' // In user_register_validate() arg(1) must be 'register' }; /** * Shows the floating window */ fw.showWindow = function(content_properties) { if(content_properties) fw.content_properties = content_properties; fw.window_obj.swapDepths({reinit:true}); fw.setContent(fw.content_proerties); }; /** * Hides the window * @param reload bool Wheter or not to reload the ajax params. * If this is false or not set, all form values are re-sent after reopening the window. */ fw.hideWindow = function(reload) { if(reload) { fw.content_properties.ajax_params = { float_window_content_func:fw.content_properties.ajax_params.float_window_content_func, is_form:fw.content_properties.ajax_params.is_form }; }; fw.window_visible = false; fw.window_obj.css({'visibility':'hidden'}); }; /** * Shows a loading image inside the content container */ fw.startLoading = function() { if(!fw.loading_img) { fw.loading_img = $('').css({ 'background':'url(' + Drupal.settings.float_window_module_path + '/images/loading.gif) 50% 50% no-repeat', 'width':'100%' }); }; fw.loading_img.height(fw.window_content_obj.height()); fw.window_content_obj.html('').parent().append(fw.loading_img); }; /** * Hides the loading image inside the content container */ fw.stopLoading = function() { if(fw.loading_img) fw.loading_img.remove(); }; /** * Aligns the window to the browsers window */ fw.align = function() { fw.getBrowserWindowDimensions(); fw.getFloatWindowDimensions(); fw.window_obj.css({ height :($.browser.msie && $.browser.version < 7) ? '10px' : 'auto', width :fw.float_win_dimensions.width + 'px', top :fw.float_win_dimensions.top + fw.browser_win_dimensions.scroll_top + 'px', left :fw.float_win_dimensions.left + 'px' }); }; /** * Returns an object of the windows dimensions */ fw.addEventListeners = function(init) { // Only on initialization if(init === true) { if(fw.resizable) { // Add the click handler to the resize button fw.resizable_button_obj.click(function() { fw.dragged = true; fw.max_min(); }); // Add the doubleclick handler to the window's title fw.window_title_obj.dblclick(function() { fw.window_obj.swapDepths({reinit:true}); fw.max_min(); }).mousedown(function() { fw.window_obj.swapDepths({reinit:true}); fw.dragged = true; }); }; fw.window_obj.mousedown(function() { fw.window_obj.swapDepths({reinit:true}); }); // If there's a close button.... if(fw.add_close_button) { fw.close_button_obj.click(function() { fw.dragged = true; fw.hideWindow(); }); }; // If the browser window is resized, check whether the floating window is maximized // If so, re-maximize the floating window, else re-align the floating window if(!$.browser.msie) { $(window).resize(function() { if(!fw.maximized) { fw.align(); } else { fw.maximize(); }; }); }; // Add the drag functionality to the window's title bar if(fw.draggable) fw.window_obj.jqDrag(fw.window_title_obj); // The show_button is a selector for the DOM element(s) which will show the window after clicking on it. if(fw.show_button) { if(!window.floatwin_show_buttons) window.floatwin_show_buttons = {}; window.floatwin_show_buttons[fw.window_id] = fw.show_button; $(fw.show_button).click(function() { fw.clicked_url = $(this).attr('href'); fw.showWindow(); return false; }); }; }; }; /** * Toggles maximization */ fw.max_min = function() { if(fw.maximized == false) { fw.maximize(); } else { fw.minimize(); }; }; /** * Maximizes the floating window */ fw.maximize = function() { $('body').css({ overflow:'hidden' }); fw.getFloatWindowDimensions(); fw.getBrowserWindowDimensions(); // Lets fix the height of the content container. // If the content is larger than the container, scrollbars are added fw.window_content_obj.css({ height :fw.browser_win_dimensions.height + (fw.margin.top + fw.margin.bottom) - (fw.window_obj.find('tr:eq(2) td:eq(0)').height() + fw.window_obj.find('tr:eq(0) td:eq(0)').height()), overflow :'auto' }); fw.window_obj.css({ width : fw.browser_win_dimensions.width + fw.margin.left + fw.margin.right + 'px', height : fw.browser_win_dimensions.height + fw.margin.top + fw.margin.bottom + 'px', top : 0 - fw.margin.top + fw.browser_win_dimensions.scroll_top + 'px', left : 0 - fw.margin.left + 'px' }); if(fw.draggable && fw.window_obj.deljqDrag) { fw.window_obj.deljqDrag(); }; fw.resizable_button_obj.addClass('maximized'); fw.maximized = true; }; /** * Minimizes the floating window */ fw.minimize = function() { $('body').css({ overflow : 'visible' }); fw.window_content_obj.css({ height :'auto', overflow :'visible' }); fw.getBrowserWindowDimensions(); fw.window_obj.css({ width : fw.float_win_dimensions.width + 'px', height : 'auto', top : fw.float_win_dimensions.top + 'px', left : fw.float_win_dimensions.left + 'px' }); if(fw.draggable) fw.window_obj.jqDrag(fw.window_title_obj); fw.resizable_button_obj.removeClass('maximized'); fw.maximized = false; }; /** * Returns an object of the browser window's dimensions */ fw.getBrowserWindowDimensions = function() { fw.browser_win_dimensions = { width: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth || 0, height: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight || 0, scroll_left: window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0, scroll_top: window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0, inner_width: window.innerWidth || document.documentElement.scrollWidth || document.body.scrollWidth || 0, inner_height: window.innerHeight || document.documentElement.scrollHeight || document.body.scrollHeight || 0 }; return fw.browser_win_dimensions; }; /** * Returns an object of the float window's dimensions * If the window hasn't been dragged before, the positions will be recalculated */ fw.getFloatWindowDimensions = function() { fw.float_win_dimensions.width = (fw.dragged) ? parseInt(fw.window_obj.css('width')) : fw.calculateWidth(); fw.float_win_dimensions.height = (fw.dragged) ? parseInt(fw.window_obj.css('height')) : fw.calculateHeight(); fw.float_win_dimensions.left = (fw.dragged) ? parseInt(fw.window_obj.css('left')) : fw.calculateLeft(); fw.float_win_dimensions.top = (fw.dragged) ? parseInt(fw.window_obj.css('top')) : fw.calculateTop(); return fw.float_win_dimensions; }; /** * Calculate the width for the floating window * If the width of the title is wider than the with gaven as setting, the title width will override the width in the options */ fw.calculateWidth = function() { // First we need to check whether the target width is larger than the tilte width. // If not, we need to use the title width. var header = fw.window_obj.find('tr:eq(0) td:eq(1) div'); var h4 = header.find('h4'); // Create a span to calculate the text inside the header title var header_temp = $('').css({'opacity':'0', 'font-size':h4.css('font-size'), 'font-weight':h4.css('font-weight'), 'font-family':h4.css('font-family')}).html(h4.html()).appendTo('body'); var title_width = header_temp.width(); header_temp.remove(); // Let's add the widths of all buttons to the title width header.find('div').each(function () { title_width += (parseInt($(this).css('width')) * 2); // We double this while we need the space for both sides of the title }); // Get the content width var content_width = ($.browser.msie) ? fw.window_content_obj.width() : parseInt(fw.window_content_obj.css('width')); var inner_width = (content_width > title_width) ? content_width : title_width; var use_width = (fw.min_width > inner_width) ? fw.min_width : inner_width; // At last we need to check wheter the browsers window isn't smaller than the targer width if(use_width > fw.browser_win_dimensions.width) use_width = fw.browser_win_dimensions.width; return fw.left_td_width + fw.right_td_width + use_width; }; /** * Calculate the height for the floating window */ fw.calculateHeight = function() { var content_height = parseInt(fw.window_obj.height()); return (content_height > fw.min_height) ? content_height : fw.min_height; }; /** * Calculate the left position for the floating window */ fw.calculateLeft = function() { var left = ((fw.browser_win_dimensions.width / 2) - (fw.float_win_dimensions.width / 2)); return (left > 0) ? left - fw.margin.left : 0 - fw.margin.left; }; /** * Calculate the top position for the floating window */ fw.calculateTop = function() { var top = ((fw.browser_win_dimensions.height / 2) - (fw.float_win_dimensions.height / 2)); return (top > 0) ? top - fw.margin.top : 0 - fw.margin.top; }; }; /** * Load appropriate scripts for the current page */ $(function() { // Check for floating window configurations if(window.float_windows_configurations !== undefined) { // There is at least one configuration. Create an object to store all floating windows window.float_windows = {}; for(var i in float_windows_configurations) { // Create an instance of a floating window window.float_windows[float_windows_configurations[i].window_id] = new floatWin(float_windows_configurations[i]); window.float_windows[float_windows_configurations[i].window_id].init(); }; delete(float_windows_configurations); }; });