diff options
author | Ctibor Brančík <ctibor@brancik.cz> | 2016-03-20 19:27:01 +0100 |
---|---|---|
committer | Ctibor Brančík <ctibor@brancik.cz> | 2016-03-20 19:27:01 +0100 |
commit | 29a6913890a675ddf1a9239b4407f105e02dc95d (patch) | |
tree | dd9ba21b73e9e704952b49d5153616a9dfa9b98f /sites/all/modules/media/js | |
parent | 5ddacae6306ce071d4f7e4d438960d6d3a4c6bd8 (diff) | |
download | brdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.gz brdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.bz2 |
Added drupal modules for site
Diffstat (limited to 'sites/all/modules/media/js')
-rw-r--r-- | sites/all/modules/media/js/media.admin.js | 77 | ||||
-rw-r--r-- | sites/all/modules/media/js/media.browser.js | 124 | ||||
-rw-r--r-- | sites/all/modules/media/js/media.core.js | 19 | ||||
-rw-r--r-- | sites/all/modules/media/js/media.js | 125 | ||||
-rw-r--r-- | sites/all/modules/media/js/media.popups.js | 384 | ||||
-rw-r--r-- | sites/all/modules/media/js/plugins/media.views.js | 173 | ||||
-rw-r--r-- | sites/all/modules/media/js/util/ba-debug.min.js | 12 | ||||
-rw-r--r-- | sites/all/modules/media/js/util/json2.js | 481 |
8 files changed, 1395 insertions, 0 deletions
diff --git a/sites/all/modules/media/js/media.admin.js b/sites/all/modules/media/js/media.admin.js new file mode 100644 index 000000000..058e9318c --- /dev/null +++ b/sites/all/modules/media/js/media.admin.js @@ -0,0 +1,77 @@ +/** + * @file + * Javascript for the interface at admin/content/media and also for interfaces + * related to setting up media fields and for media type administration. + * + * Basically, if it's on the /admin path, it's probably here. + */ + +(function ($) { + +/** + * Functionality for the administrative file listings. + */ +Drupal.behaviors.mediaAdmin = { + attach: function (context) { + // Show a javascript confirmation dialog if a user has files selected and + // they try to switch between the "Thumbnail" and "List" local tasks. + $('.tabs.secondary a').once('media-admin').bind('click', function () { + if ($(':checkbox:checked', $('.file-entity-admin-file-form')).length != 0) { + return confirm(Drupal.t('If you switch views, you will lose your selection.')); + } + }); + + if ($('.media-display-thumbnails').length && !$('.media-thumbnails-select').length) { + // Implements 'select all/none' for thumbnail view. + // @TODO: Support grabbing more than one page of thumbnails. + var allLink = $('<a href="#">' + Drupal.t('all') + '</a>') + .click(function () { + $('.media-display-thumbnails', $(this).parents('form')).find(':checkbox').attr('checked', true).change(); + return false; + }); + var noneLink = $('<a href="#">' + Drupal.t('none') + '</a>') + .click(function () { + $('.media-display-thumbnails', $(this).parents('form')).find(':checkbox').attr('checked', false).change(); + return false; + }); + $('<div class="media-thumbnails-select" />') + .append('<strong>' + Drupal.t('Select') + ':</strong> ') + .append(allLink) + .append(', ') + .append(noneLink) + .prependTo('.media-display-thumbnails') + // If the media item is clicked anywhere other than on the image itself + // check the checkbox. For the record, JS thinks this is wonky. + $('.media-item').bind('click', function (e) { + if ($(e.target).is('img, a')) { + return; + } + var checkbox = $(this).parent().find(':checkbox'); + if (checkbox.is(':checked')) { + checkbox.attr('checked', false).change(); + } else { + checkbox.attr('checked', true).change(); + } + }); + + // Add an extra class to selected thumbnails. + $('.media-display-thumbnails :checkbox').each(function () { + var checkbox = $(this); + if (checkbox.is(':checked')) { + $(checkbox.parents('li').find('.media-item')).addClass('selected'); + } + + checkbox.bind('change.media', function () { + if (checkbox.is(':checked')) { + $(checkbox.parents('li').find('.media-item')).addClass('selected'); + } + else { + $(checkbox.parents('li').find('.media-item')).removeClass('selected'); + } + }); + }); + } + } +}; + +})(jQuery); diff --git a/sites/all/modules/media/js/media.browser.js b/sites/all/modules/media/js/media.browser.js new file mode 100644 index 000000000..88490e598 --- /dev/null +++ b/sites/all/modules/media/js/media.browser.js @@ -0,0 +1,124 @@ +/** + * @file + * Provides default functions for the media browser + */ + +(function ($) { +namespace('Drupal.media.browser'); + +Drupal.media.browser.selectedMedia = []; +Drupal.media.browser.mediaAdded = function () {}; +Drupal.media.browser.selectionFinalized = function (selectedMedia) { + // This is intended to be overridden if a callee wants to be triggered + // when the media selection is finalized from inside the browser. + // This is used for the file upload form for instance. +}; + +Drupal.behaviors.MediaBrowser = { + attach: function (context) { + if (Drupal.settings.media && Drupal.settings.media.selectedMedia) { + Drupal.media.browser.selectMedia(Drupal.settings.media.selectedMedia); + // Fire a confirmation of some sort. + Drupal.media.browser.finalizeSelection(); + } + + // Instantiate the tabs. + var showFunc = function(event, ui) { + // Store index of the tab being activated. + if (parent_iframe = Drupal.media.browser.getParentIframe(window)) { + $(parent_iframe).attr('current_tab', $('#media-tabs-wrapper > ul > li.ui-state-active').index()); + } + }; + var activeTab = Drupal.media.browser.tabFromHash(); + $('#media-browser-tabset').once('MediaBrowser').tabs({ + selected: activeTab, // jquery < 1.9 + active: activeTab, // jquery >= 1.9 + show: showFunc, // jquery ui < 1.8 + activate: showFunc // jquery ui >= 1.8 + }); + + $('.media-browser-tab').each( Drupal.media.browser.validateButtons ); + } + // Wait for additional params to be passed in. +}; + +Drupal.media.browser.getParentIframe = function (window) { + var arrFrames = parent.document.getElementsByTagName("IFRAME"); + for (var i = 0; i < arrFrames.length; i++) { + if (arrFrames[i].contentWindow === window) { + return arrFrames[i]; + } + } +} + +/** + * Get index of the active tab from window.location.hash + */ +Drupal.media.browser.tabFromHash = function () { + if (parent_iframe = Drupal.media.browser.getParentIframe(window)) { + return $(parent_iframe).attr('current_tab'); + } + return 0; +}; + +Drupal.media.browser.launch = function () { + +}; + +Drupal.media.browser.validateButtons = function() { + // The media browser runs in an IFRAME. The Drupal.media.popups.mediaBrowser() + // function sets up the IFRAME and an "OK" button that is outside of the + // IFRAME, so that its click handlers can destroy the IFRAME while retaining + // information about what media items were selected. However, Drupal UI + // convention is to place all action buttons on the same "line" at the bottom + // of the form, so if the form within the IFRAME contains a "Submit" button or + // other action buttons, then the "OK" button will appear below the IFRAME + // which breaks this convention and is confusing to the user. Therefore, we + // add a "Submit" button inside the IFRAME, and have its click action trigger + // the click action of the corresponding "OK" button that is outside the + // IFRAME. media.css contains CSS rules that hide the outside buttons. + + // If a submit button is present, another round-trip to the server is needed + // before the user's selection is finalized. For these cases, when the form's + // real Submit button is clicked, the server either returns another form for + // the user to fill out, or else a completion page that contains or sets the + // Drupal.media.browser.selectedMedia variable. If the latter, then + // Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad() auto-triggers the + // "OK" button action to finalize the selection and remove the IFRAME. + + // We need to check for the fake submit button that is used on non-form based + // pane content. On these items we need to bind the clicks so that media can + // be selected or the window can be closed. This is still a hacky approach, + // but it is a step in the right direction. + + $('a.button.fake-submit', this).once().bind('click', Drupal.media.browser.submit); +}; + +Drupal.media.browser.submit = function () { + // @see Drupal.media.browser.validateButtons(). + var buttons = $(parent.window.document.body).find('#mediaBrowser').parent('.ui-dialog').find('.ui-dialog-buttonpane button'); + buttons[0].click(); + + // Return false to prevent the fake link "click" from continuing. + return false; +} + +Drupal.media.browser.selectMedia = function (selectedMedia) { + Drupal.media.browser.selectedMedia = selectedMedia; +}; + +Drupal.media.browser.selectMediaAndSubmit = function (selectedMedia) { + Drupal.media.browser.selectedMedia = selectedMedia; + Drupal.media.browser.submit(); +}; + +Drupal.media.browser.finalizeSelection = function () { + if (!Drupal.media.browser.selectedMedia) { + throw new exception(Drupal.t('Cannot continue, nothing selected')); + } + else { + Drupal.media.browser.selectionFinalized(Drupal.media.browser.selectedMedia); + } +}; + +}(jQuery)); diff --git a/sites/all/modules/media/js/media.core.js b/sites/all/modules/media/js/media.core.js new file mode 100644 index 000000000..f99971c85 --- /dev/null +++ b/sites/all/modules/media/js/media.core.js @@ -0,0 +1,19 @@ + +/** + * Creates a namespace. + * + * @return + * The created namespace object. + */ +function namespace () { + var a=arguments, o=null, i, j, d; + for (i=0; i<a.length; i=i+1) { + d=a[i].split("."); + o=window; + for (j=0; j<d.length; j=j+1) { + o[d[j]]=o[d[j]] || {}; + o=o[d[j]]; + } + } + return o; +}; diff --git a/sites/all/modules/media/js/media.js b/sites/all/modules/media/js/media.js new file mode 100644 index 000000000..5288dd307 --- /dev/null +++ b/sites/all/modules/media/js/media.js @@ -0,0 +1,125 @@ +/** + * @file + * Provides JavaScript additions to the media field widget. + * + * This file provides support for launching the media browser to select existing + * files and disabling of other media fields during Ajax uploads (which prevents + * separate media fields from accidentally attaching files). + */ + +(function ($) { + +/** + * Attach behaviors to media element browse fields. + */ +Drupal.behaviors.mediaElement = { + attach: function (context, settings) { + if (settings.media && settings.media.elements) { + $.each(settings.media.elements, function(selector) { + $(selector, context).once('media-browser-launch', function () { + var configuration = settings.media.elements[selector]; + // The user has JavaScript enabled, so display the browse field and hide + // the upload and attach fields which are only used as a fallback in + // case the user is unable to use the media browser. + $(selector, context).children('.browse').show(); + $(selector, context).children('.upload').hide(); + $(selector, context).children('.attach').hide(); + $(selector, context).children('.browse').bind('click', {configuration: configuration}, Drupal.media.openBrowser); + }); + }); + } + } +}; + +/** + * Attach behaviors to the media attach and remove buttons. + */ +Drupal.behaviors.mediaButtons = { + attach: function (context) { + $('input.form-submit', context).bind('mousedown', Drupal.media.disableFields); + }, + detach: function (context) { + $('input.form-submit', context).unbind('mousedown', Drupal.media.disableFields); + } +}; + +/** + * Media attach utility functions. + */ +Drupal.media = Drupal.media || {}; + +/** + * Opens the media browser with the element's configuration settings. + */ +Drupal.media.openBrowser = function (event) { + var clickedButton = this; + var configuration = event.data.configuration.global; + + // Find the file ID, preview and upload fields. + var fidField = $(this).siblings('.fid'); + var previewField = $(this).siblings('.preview'); + var uploadField = $(this).siblings('.upload'); + + // Find the edit and remove buttons. + var editButton = $(this).siblings('.edit'); + var removeButton = $(this).siblings('.remove'); + + // Launch the media browser. + Drupal.media.popups.mediaBrowser(function (mediaFiles) { + // Ensure that there was at least one media file selected. + if (mediaFiles.length < 0) { + return; + } + + // Grab the first of the selected media files. + var mediaFile = mediaFiles[0]; + + // Set the value of the hidden file ID field and trigger a change. + uploadField.val(mediaFile.fid); + uploadField.trigger('change'); + + // Find the attach button and automatically trigger it. + var attachButton = uploadField.siblings('.attach'); + attachButton.trigger('mousedown'); + + // Display a preview of the file using the selected media file's display. + previewField.html(mediaFile.preview); + }, configuration); + + return false; +}; + +/** + * Prevent media browsing when using buttons not intended to browse. + */ +Drupal.media.disableFields = function (event) { + var clickedButton = this; + + // Only disable browse fields for Ajax buttons. + if (!$(clickedButton).hasClass('ajax-processed')) { + return; + } + + // Check if we're working with an "Attach" button. + var $enabledFields = []; + if ($(this).closest('div.media-widget').length > 0) { + $enabledFields = $(this).closest('div.media-widget').find('input.attach'); + } + + // Temporarily disable attach fields other than the one we're currently + // working with. Filter out fields that are already disabled so that they + // do not get enabled when we re-enable these fields at the end of behavior + // processing. Re-enable in a setTimeout set to a relatively short amount + // of time (1 second). All the other mousedown handlers (like Drupal's Ajax + // behaviors) are excuted before any timeout functions are called, so we + // don't have to worry about the fields being re-enabled too soon. + // @todo If the previous sentence is true, why not set the timeout to 0? + var $fieldsToTemporarilyDisable = $('div.media-widget input.attach').not($enabledFields).not(':disabled'); + $fieldsToTemporarilyDisable.attr('disabled', 'disabled'); + setTimeout(function (){ + $fieldsToTemporarilyDisable.attr('disabled', false); + }, 1000); +}; + +})(jQuery); + diff --git a/sites/all/modules/media/js/media.popups.js b/sites/all/modules/media/js/media.popups.js new file mode 100644 index 000000000..2abb96e6f --- /dev/null +++ b/sites/all/modules/media/js/media.popups.js @@ -0,0 +1,384 @@ + +/** + * @file: Popup dialog interfaces for the media project. + * + * Drupal.media.popups.mediaBrowser + * Launches the media browser which allows users to pick a piece of media. + * + * Drupal.media.popups.mediaStyleSelector + * Launches the style selection form where the user can choose + * what format / style they want their media in. + * + */ + +(function ($) { +namespace('Drupal.media.popups'); + +/** + * Media browser popup. Creates a media browser dialog. + * + * @param {function} + * onSelect Callback for when dialog is closed, received (Array + * media, Object extra); + * @param {Object} + * globalOptions Global options that will get passed upon initialization of the browser. + * @see Drupal.media.popups.mediaBrowser.getDefaults(); + * + * @param {Object} + * pluginOptions Options for specific plugins. These are passed + * to the plugin upon initialization. If a function is passed here as + * a callback, it is obviously not passed, but is accessible to the plugin + * in Drupal.settings.variables. + * + * Example + * pluginOptions = {library: {url_include_patterns:'/foo/bar'}}; + * + * @param {Object} + * widgetOptions Options controlling the appearance and behavior of the + * modal dialog. + * @see Drupal.media.popups.mediaBrowser.getDefaults(); + */ +Drupal.media.popups.mediaBrowser = function (onSelect, globalOptions, pluginOptions, widgetOptions) { + var options = Drupal.media.popups.mediaBrowser.getDefaults(); + options.global = $.extend({}, options.global, globalOptions); + options.plugins = pluginOptions; + options.widget = $.extend({}, options.widget, widgetOptions); + + // Create it as a modal window. + var browserSrc = options.widget.src; + if ($.isArray(browserSrc) && browserSrc.length) { + browserSrc = browserSrc[browserSrc.length - 1]; + } + // Params to send along to the iframe. WIP. + var params = {}; + $.extend(params, options.global); + params.plugins = options.plugins; + + browserSrc += '&' + $.param(params); + var mediaIframe = Drupal.media.popups.getPopupIframe(browserSrc, 'mediaBrowser'); + // Attach the onLoad event + mediaIframe.bind('load', options, options.widget.onLoad); + + /** + * Setting up the modal dialog + */ + var ok = 'OK'; + var notSelected = 'You have not selected anything!'; + + if (Drupal && Drupal.t) { + ok = Drupal.t(ok); + notSelected = Drupal.t(notSelected); + } + + // @todo: let some options come through here. Currently can't be changed. + var dialogOptions = options.dialog; + + dialogOptions.buttons[ok] = function () { + var selected = this.contentWindow.Drupal.media.browser.selectedMedia; + if (selected.length < 1) { + alert(notSelected); + return; + } + onSelect(selected); + $(this).dialog("close"); + }; + + var dialog = mediaIframe.dialog(dialogOptions); + + Drupal.media.popups.sizeDialog(dialog); + Drupal.media.popups.resizeDialog(dialog); + Drupal.media.popups.scrollDialog(dialog); + Drupal.media.popups.overlayDisplace(dialog.parents(".ui-dialog")); + + return mediaIframe; +}; + +Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad = function (e) { + var options = e.data; + if (this.contentWindow.Drupal.media == undefined) return; + + if (this.contentWindow.Drupal.media.browser.selectedMedia.length > 0) { + var ok = (Drupal && Drupal.t) ? Drupal.t('OK') : 'OK'; + var ok_func = $(this).dialog('option', 'buttons')[ok]; + ok_func.call(this); + return; + } +}; + +Drupal.media.popups.mediaBrowser.getDefaults = function () { + return { + global: { + types: [], // Types to allow, defaults to all. + activePlugins: [] // If provided, a list of plugins which should be enabled. + }, + widget: { // Settings for the actual iFrame which is launched. + src: Drupal.settings.media.browserUrl, // Src of the media browser (if you want to totally override it) + onLoad: Drupal.media.popups.mediaBrowser.mediaBrowserOnLoad // Onload function when iFrame loads. + }, + dialog: Drupal.media.popups.getDialogOptions() + }; +}; + +Drupal.media.popups.mediaBrowser.finalizeSelection = function () { + var selected = this.contentWindow.Drupal.media.browser.selectedMedia; + if (selected.length < 1) { + alert(notSelected); + return; + } + onSelect(selected); + $(this).dialog("close"); +} + +/** + * Style chooser Popup. Creates a dialog for a user to choose a media style. + * + * @param mediaFile + * The mediaFile you are requesting this formatting form for. + * @todo: should this be fid? That's actually all we need now. + * + * @param Function + * onSubmit Function to be called when the user chooses a media + * style. Takes one parameter (Object formattedMedia). + * + * @param Object + * options Options for the mediaStyleChooser dialog. + */ +Drupal.media.popups.mediaStyleSelector = function (mediaFile, onSelect, options) { + var defaults = Drupal.media.popups.mediaStyleSelector.getDefaults(); + // @todo: remove this awful hack :( + if (typeof defaults.src === 'string' ) { + defaults.src = defaults.src.replace('-media_id-', mediaFile.fid) + '&fields=' + encodeURIComponent(JSON.stringify(mediaFile.fields)); + } + else { + var src = defaults.src.shift(); + defaults.src.unshift(src); + defaults.src = src.replace('-media_id-', mediaFile.fid) + '&fields=' + encodeURIComponent(JSON.stringify(mediaFile.fields)); + } + options = $.extend({}, defaults, options); + // Create it as a modal window. + var mediaIframe = Drupal.media.popups.getPopupIframe(options.src, 'mediaStyleSelector'); + // Attach the onLoad event + mediaIframe.bind('load', options, options.onLoad); + + /** + * Set up the button text + */ + var ok = 'OK'; + var notSelected = 'Very sorry, there was an unknown error embedding media.'; + + if (Drupal && Drupal.t) { + ok = Drupal.t(ok); + notSelected = Drupal.t(notSelected); + } + + // @todo: let some options come through here. Currently can't be changed. + var dialogOptions = Drupal.media.popups.getDialogOptions(); + + dialogOptions.buttons[ok] = function () { + + var formattedMedia = this.contentWindow.Drupal.media.formatForm.getFormattedMedia(); + if (!formattedMedia) { + alert(notSelected); + return; + } + onSelect(formattedMedia); + $(this).dialog("close"); + }; + + var dialog = mediaIframe.dialog(dialogOptions); + + Drupal.media.popups.sizeDialog(dialog); + Drupal.media.popups.resizeDialog(dialog); + Drupal.media.popups.scrollDialog(dialog); + Drupal.media.popups.overlayDisplace(dialog.parents(".ui-dialog")); + + return mediaIframe; +}; + +Drupal.media.popups.mediaStyleSelector.mediaBrowserOnLoad = function (e) { +}; + +Drupal.media.popups.mediaStyleSelector.getDefaults = function () { + return { + src: Drupal.settings.media.styleSelectorUrl, + onLoad: Drupal.media.popups.mediaStyleSelector.mediaBrowserOnLoad + }; +}; + + +/** + * Style chooser Popup. Creates a dialog for a user to choose a media style. + * + * @param mediaFile + * The mediaFile you are requesting this formatting form for. + * @todo: should this be fid? That's actually all we need now. + * + * @param Function + * onSubmit Function to be called when the user chooses a media + * style. Takes one parameter (Object formattedMedia). + * + * @param Object + * options Options for the mediaStyleChooser dialog. + */ +Drupal.media.popups.mediaFieldEditor = function (fid, onSelect, options) { + var defaults = Drupal.media.popups.mediaFieldEditor.getDefaults(); + // @todo: remove this awful hack :( + defaults.src = defaults.src.replace('-media_id-', fid); + options = $.extend({}, defaults, options); + // Create it as a modal window. + var mediaIframe = Drupal.media.popups.getPopupIframe(options.src, 'mediaFieldEditor'); + // Attach the onLoad event + // @TODO - This event is firing too early in IE on Windows 7, + // - so the height being calculated is too short for the content. + mediaIframe.bind('load', options, options.onLoad); + + /** + * Set up the button text + */ + var ok = 'OK'; + var notSelected = 'Very sorry, there was an unknown error embedding media.'; + + if (Drupal && Drupal.t) { + ok = Drupal.t(ok); + notSelected = Drupal.t(notSelected); + } + + // @todo: let some options come through here. Currently can't be changed. + var dialogOptions = Drupal.media.popups.getDialogOptions(); + + dialogOptions.buttons[ok] = function () { + var formattedMedia = this.contentWindow.Drupal.media.formatForm.getFormattedMedia(); + if (!formattedMedia) { + alert(notSelected); + return; + } + onSelect(formattedMedia); + $(this).dialog("close"); + }; + + var dialog = mediaIframe.dialog(dialogOptions); + + Drupal.media.popups.sizeDialog(dialog); + Drupal.media.popups.resizeDialog(dialog); + Drupal.media.popups.scrollDialog(dialog); + Drupal.media.popups.overlayDisplace(dialog); + + return mediaIframe; +}; + +Drupal.media.popups.mediaFieldEditor.mediaBrowserOnLoad = function (e) { + +}; + +Drupal.media.popups.mediaFieldEditor.getDefaults = function () { + return { + // @todo: do this for real + src: '/media/-media_id-/edit?render=media-popup', + onLoad: Drupal.media.popups.mediaFieldEditor.mediaBrowserOnLoad + }; +}; + + +/** + * Generic functions to both the media-browser and style selector + */ + +/** + * Returns the commonly used options for the dialog. + */ +Drupal.media.popups.getDialogOptions = function () { + return { + buttons: {}, + dialogClass: Drupal.settings.media.dialogOptions.dialogclass, + modal: Drupal.settings.media.dialogOptions.modal, + draggable: Drupal.settings.media.dialogOptions.draggable, + resizable: Drupal.settings.media.dialogOptions.resizable, + minWidth: Drupal.settings.media.dialogOptions.minwidth, + width: Drupal.settings.media.dialogOptions.width, + height: Drupal.settings.media.dialogOptions.height, + position: Drupal.settings.media.dialogOptions.position, + overlay: { + backgroundColor: Drupal.settings.media.dialogOptions.overlay.backgroundcolor, + opacity: Drupal.settings.media.dialogOptions.overlay.opacity + }, + zIndex: Drupal.settings.media.dialogOptions.zindex, + close: function (event, ui) { + $(event.target).remove(); + } + }; +}; + +/** + * Get an iframe to serve as the dialog's contents. Common to both plugins. + */ +Drupal.media.popups.getPopupIframe = function (src, id, options) { + var defaults = {width: '100%', scrolling: 'auto'}; + var options = $.extend({}, defaults, options); + + return $('<iframe class="media-modal-frame"/>') + .attr('src', src) + .attr('width', options.width) + .attr('id', id) + .attr('scrolling', options.scrolling); +}; + +Drupal.media.popups.overlayDisplace = function (dialog) { + if (parent.window.Drupal.overlay && jQuery.isFunction(parent.window.Drupal.overlay.getDisplacement)) { + var overlayDisplace = parent.window.Drupal.overlay.getDisplacement('top'); + if (dialog.offset().top < overlayDisplace) { + dialog.css('top', overlayDisplace); + } + } +} + +/** + * Size the dialog when it is first loaded and keep it centered when scrolling. + * + * @param jQuery dialogElement + * The element which has .dialog() attached to it. + */ +Drupal.media.popups.sizeDialog = function (dialogElement) { + if (!dialogElement.is(':visible')) { + return; + } + var windowWidth = $(window).width(); + var dialogWidth = windowWidth * 0.8; + var windowHeight = $(window).height(); + var dialogHeight = windowHeight * 0.8; + + dialogElement.dialog("option", "width", dialogWidth); + dialogElement.dialog("option", "height", dialogHeight); + dialogElement.dialog("option", "position", 'center'); + + $('.media-modal-frame').width('100%'); +} + +/** + * Resize the dialog when the window changes. + * + * @param jQuery dialogElement + * The element which has .dialog() attached to it. + */ +Drupal.media.popups.resizeDialog = function (dialogElement) { + $(window).resize(function() { + Drupal.media.popups.sizeDialog(dialogElement); + }); +} + +/** + * Keeps the dialog centered when the window is scrolled. + * + * @param jQuery dialogElement + * The element which has .dialog() attached to it. + */ +Drupal.media.popups.scrollDialog = function (dialogElement) { + // Keep the dialog window centered when scrolling. + $(window).scroll(function() { + if (!dialogElement.is(':visible')) { + return; + } + dialogElement.dialog("option", "position", 'center'); + }); +} + +})(jQuery); diff --git a/sites/all/modules/media/js/plugins/media.views.js b/sites/all/modules/media/js/plugins/media.views.js new file mode 100644 index 000000000..455288d65 --- /dev/null +++ b/sites/all/modules/media/js/plugins/media.views.js @@ -0,0 +1,173 @@ +/** + * @file + * Handles the JS for the views file browser. + * + * Note that this does not currently support multiple file selection + */ + +(function ($) { + +namespace('Drupal.media.browser.views'); +Drupal.behaviors.mediaViews = { + attach: function (context, settings) { + + // Make sure when pressing enter on text inputs, the form isn't submitted + $('.ctools-auto-submit-full-form .views-exposed-form input:text, input:text.ctools-auto-submit', context) + .filter(':not(.ctools-auto-submit-exclude)') + .bind('keydown keyup', function (e) { + if(e.keyCode === 13) { + e.stopImmediatePropagation(); + e.preventDefault(); + } + }); + // Disable the links on media items list + $('.view-content ul.media-list-thumbnails a').click(function() { + return false; + }); + + // We loop through the views listed in Drupal.settings.media.browser.views + // and set them up individually. + var views_ids = []; + for(var key in Drupal.settings.media.browser.views){ + views_ids.push(key); + } + + for (var i = 0; i < views_ids.length; i++) { + var views_id = views_ids[i]; + for (var j= 0; j < Drupal.settings.media.browser.views[views_id].length; j++) { + var views_display_id = Drupal.settings.media.browser.views[views_id][j], + view = $('.view-id-' + views_id + '.view-display-id-' + views_display_id); + if (view.length) { + Drupal.media.browser.views.setup(view); + } + } + } + + // Reset the state on tab-changes- bind on the 'select' event on the tabset + $('#media-browser-tabset').bind('tabsselect', function(event, ui) { + var view = $('.view', ui.panel); + if (view.length) { + Drupal.media.browser.views.select(view); + } + }); + + } +} + +/** + * Event-function that is called with a view, when the tab containing that + * view is selected. + */ +Drupal.media.browser.views.select = function(view) { + // Reset the list of selected files + Drupal.media.browser.selectMedia([]); + + // Reset all 'selected'-status. + $('.view-content .media-item', view).removeClass('selected'); +} + +/** + * Setup function. Called once for every Media Browser view. + * + * Sets up event-handlers for selecting items in the view. + */ +Drupal.media.browser.views.setup = function(view) { + // Ensure we only setup each view once.. + if ($(view).hasClass('media-browser-views-processed')) { + return; + } + + // Reset the list of selected files + Drupal.media.browser.selectMedia([]); + + // Catch double click to submit a single item. + $('.view-content .media-item', view).bind('dblclick', function () { + var fid = $(this).closest('.media-item[data-fid]').data('fid'), + selectedFiles = new Array(); + + // Remove all currently selected files + $('.view-content .media-item', view).removeClass('selected'); + + // Mark it as selected + $(this).addClass('selected'); + + // Because the files are added using drupal_add_js() and due to the fact + // that drupal_get_js() runs a drupal_array_merge_deep() which re-numbers + // numeric key values, we have to search in Drupal.settings.media.files + // for the matching file ID rather than referencing it directly. + for (index in Drupal.settings.media.files) { + if (Drupal.settings.media.files[index].fid == fid) { + selectedFiles.push(Drupal.settings.media.files[index]); + + // If multiple tabs contains the same file, it will be present in the + // files-array multiple times, so we break out early so we don't have + // it in the selectedFiles array multiple times. + // This would interfer with multi-selection, so... + break; + } + } + Drupal.media.browser.selectMediaAndSubmit(selectedFiles); + }); + + + // Catch the click on a media item + $('.view-content .media-item', view).bind('click', function () { + var fid = $(this).closest('.media-item[data-fid]').data('fid'), + selectedFiles = new Array(); + + // Remove all currently selected files + $('.view-content .media-item', view).removeClass('selected'); + + // Mark it as selected + $(this).addClass('selected'); + + // Multiselect! + if (Drupal.settings.media.browser.params.multiselect) { + // Loop through the already selected files + for (index in Drupal.media.browser.selectedMedia) { + var currentFid = Drupal.media.browser.selectedMedia[index].fid; + + // If the current file exists in the list of already selected + // files, we deselect instead of selecting + if (currentFid == fid) { + $(this).removeClass('selected'); + // If we change the fid, the later matching won't + // add it back again because it can't find it. + fid = NaN; + + // The previously selected file wasn't clicked, so we retain it + // as an active file + } + else { + // Add to list of already selected files + selectedFiles.push(Drupal.media.browser.selectedMedia[index]); + + // Mark it as selected + $('.view-content *[data-fid=' + currentFid + '].media-item', view).addClass('selected'); + } + } + } + + // Because the files are added using drupal_add_js() and due to the fact + // that drupal_get_js() runs a drupal_array_merge_deep() which re-numbers + // numeric key values, we have to search in Drupal.settings.media.files + // for the matching file ID rather than referencing it directly. + for (index in Drupal.settings.media.files) { + if (Drupal.settings.media.files[index].fid == fid) { + selectedFiles.push(Drupal.settings.media.files[index]); + + // If multiple tabs contains the same file, it will be present in the + // files-array multiple times, so we break out early so we don't have + // it in the selectedFiles array multiple times. + // This would interfer with multi-selection, so... + break; + } + } + Drupal.media.browser.selectMedia(selectedFiles); + }); + + // Add the processed class, so we dont accidentally process the same element twice.. + $(view).addClass('media-browser-views-processed'); +} + +}(jQuery)); diff --git a/sites/all/modules/media/js/util/ba-debug.min.js b/sites/all/modules/media/js/util/ba-debug.min.js new file mode 100644 index 000000000..1c50e7fb8 --- /dev/null +++ b/sites/all/modules/media/js/util/ba-debug.min.js @@ -0,0 +1,12 @@ +/* + * debug - v0.3 - 6/8/2009 + * http://benalman.com/projects/javascript-debug-console-log/ + * + * Copyright (c) 2009 "Cowboy" Ben Alman + * Licensed under the MIT license + * http://benalman.com/about/license/ + * + * With lots of help from Paul Irish! + * http://paulirish.com/ + */ +window.debug=(function(){var c=this,e=Array.prototype.slice,b=c.console,i={},f,g,j=9,d=["error","warn","info","debug","log"],m="assert clear count dir dirxml group groupEnd profile profileEnd time timeEnd trace".split(" "),k=m.length,a=[];while(--k>=0){(function(n){i[n]=function(){j!==0&&b&&b[n]&&b[n].apply(b,arguments)}})(m[k])}k=d.length;while(--k>=0){(function(n,o){i[o]=function(){var q=e.call(arguments),p=[o].concat(q);a.push(p);h(p);if(!b||!l(n)){return}b.firebug?b[o].apply(c,q):b[o]?b[o](q):b.log(q)}})(k,d[k])}function h(n){if(f&&(g||!b||!b.log)){f.apply(c,n)}}i.setLevel=function(n){j=typeof n==="number"?n:9};function l(n){return j>0?j>n:d.length+j<=n}i.setCallback=function(){var o=e.call(arguments),n=a.length,p=n;f=o.shift()||null;g=typeof o[0]==="boolean"?o.shift():false;p-=typeof o[0]==="number"?o.shift():n;while(p<n){h(a[p++])}};return i})();
\ No newline at end of file diff --git a/sites/all/modules/media/js/util/json2.js b/sites/all/modules/media/js/util/json2.js new file mode 100644 index 000000000..39d8f3706 --- /dev/null +++ b/sites/all/modules/media/js/util/json2.js @@ -0,0 +1,481 @@ +/* + http://www.JSON.org/json2.js + 2009-09-29 + + Public Domain. + + NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. + + See http://www.JSON.org/js.html + + + This code should be minified before deployment. + See http://javascript.crockford.com/jsmin.html + + USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO + NOT CONTROL. + + + This file creates a global JSON object containing two methods: stringify + and parse. + + JSON.stringify(value, replacer, space) + value any JavaScript value, usually an object or array. + + replacer an optional parameter that determines how object + values are stringified for objects. It can be a + function or an array of strings. + + space an optional parameter that specifies the indentation + of nested structures. If it is omitted, the text will + be packed without extra whitespace. If it is a number, + it will specify the number of spaces to indent at each + level. If it is a string (such as '\t' or ' '), + it contains the characters used to indent at each level. + + This method produces a JSON text from a JavaScript value. + + When an object value is found, if the object contains a toJSON + method, its toJSON method will be called and the result will be + stringified. A toJSON method does not serialize: it returns the + value represented by the name/value pair that should be serialized, + or undefined if nothing should be serialized. The toJSON method + will be passed the key associated with the value, and this will be + bound to the value + + For example, this would serialize Dates as ISO strings. + + Date.prototype.toJSON = function (key) { + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + return this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z'; + }; + + You can provide an optional replacer method. It will be passed the + key and value of each member, with this bound to the containing + object. The value that is returned from your method will be + serialized. If your method returns undefined, then the member will + be excluded from the serialization. + + If the replacer parameter is an array of strings, then it will be + used to select the members to be serialized. It filters the results + such that only members with keys listed in the replacer array are + stringified. + + Values that do not have JSON representations, such as undefined or + functions, will not be serialized. Such values in objects will be + dropped; in arrays they will be replaced with null. You can use + a replacer function to replace those with JSON values. + JSON.stringify(undefined) returns undefined. + + The optional space parameter produces a stringification of the + value that is filled with line breaks and indentation to make it + easier to read. + + If the space parameter is a non-empty string, then that string will + be used for indentation. If the space parameter is a number, then + the indentation will be that many spaces. + + Example: + + text = JSON.stringify(['e', {pluribus: 'unum'}]); + // text is '["e",{"pluribus":"unum"}]' + + + text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t'); + // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]' + + text = JSON.stringify([new Date()], function (key, value) { + return this[key] instanceof Date ? + 'Date(' + this[key] + ')' : value; + }); + // text is '["Date(---current time---)"]' + + + JSON.parse(text, reviver) + This method parses a JSON text to produce an object or array. + It can throw a SyntaxError exception. + + The optional reviver parameter is a function that can filter and + transform the results. It receives each of the keys and values, + and its return value is used instead of the original value. + If it returns what it received, then the structure is not modified. + If it returns undefined then the member is deleted. + + Example: + + // Parse the text. Values that look like ISO date strings will + // be converted to Date objects. + + myData = JSON.parse(text, function (key, value) { + var a; + if (typeof value === 'string') { + a = +/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value); + if (a) { + return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], + +a[5], +a[6])); + } + } + return value; + }); + + myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) { + var d; + if (typeof value === 'string' && + value.slice(0, 5) === 'Date(' && + value.slice(-1) === ')') { + d = new Date(value.slice(5, -1)); + if (d) { + return d; + } + } + return value; + }); + + + This is a reference implementation. You are free to copy, modify, or + redistribute. +*/ + +/*jslint evil: true, strict: false */ + +/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply, + call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours, + getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join, + lastIndex, length, parse, prototype, push, replace, slice, stringify, + test, toJSON, toString, valueOf +*/ + + +// Create a JSON object only if one does not already exist. We create the +// methods in a closure to avoid creating global variables. + +if (!this.JSON) { + this.JSON = {}; +} + +(function () { + + function f(n) { + // Format integers to have at least two digits. + return n < 10 ? '0' + n : n; + } + + if (typeof Date.prototype.toJSON !== 'function') { + + Date.prototype.toJSON = function (key) { + + return isFinite(this.valueOf()) ? + this.getUTCFullYear() + '-' + + f(this.getUTCMonth() + 1) + '-' + + f(this.getUTCDate()) + 'T' + + f(this.getUTCHours()) + ':' + + f(this.getUTCMinutes()) + ':' + + f(this.getUTCSeconds()) + 'Z' : null; + }; + + String.prototype.toJSON = + Number.prototype.toJSON = + Boolean.prototype.toJSON = function (key) { + return this.valueOf(); + }; + } + + var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, + gap, + indent, + meta = { // table of character substitutions + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '"' : '\\"', + '\\': '\\\\' + }, + rep; + + + function quote(string) { + +// If the string contains no control characters, no quote characters, and no +// backslash characters, then we can safely slap some quotes around it. +// Otherwise we must also replace the offending characters with safe escape +// sequences. + + escapable.lastIndex = 0; + return escapable.test(string) ? + '"' + string.replace(escapable, function (a) { + var c = meta[a]; + return typeof c === 'string' ? c : + '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }) + '"' : + '"' + string + '"'; + } + + + function str(key, holder) { + +// Produce a string from holder[key]. + + var i, // The loop counter. + k, // The member key. + v, // The member value. + length, + mind = gap, + partial, + value = holder[key]; + +// If the value has a toJSON method, call it to obtain a replacement value. + + if (value && typeof value === 'object' && + typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + +// If we were called with a replacer function, then call the replacer to +// obtain a replacement value. + + if (typeof rep === 'function') { + value = rep.call(holder, key, value); + } + +// What happens next depends on the value's type. + + switch (typeof value) { + case 'string': + return quote(value); + + case 'number': + +// JSON numbers must be finite. Encode non-finite numbers as null. + + return isFinite(value) ? String(value) : 'null'; + + case 'boolean': + case 'null': + +// If the value is a boolean or null, convert it to a string. Note: +// typeof null does not produce 'null'. The case is included here in +// the remote chance that this gets fixed someday. + + return String(value); + +// If the type is 'object', we might be dealing with an object or an array or +// null. + + case 'object': + +// Due to a specification blunder in ECMAScript, typeof null is 'object', +// so watch out for that case. + + if (!value) { + return 'null'; + } + +// Make an array to hold the partial results of stringifying this object value. + + gap += indent; + partial = []; + +// Is the value an array? + + if (Object.prototype.toString.apply(value) === '[object Array]') { + +// The value is an array. Stringify every element. Use null as a placeholder +// for non-JSON values. + + length = value.length; + for (i = 0; i < length; i += 1) { + partial[i] = str(i, value) || 'null'; + } + +// Join all of the elements together, separated with commas, and wrap them in +// brackets. + + v = partial.length === 0 ? '[]' : + gap ? '[\n' + gap + + partial.join(',\n' + gap) + '\n' + + mind + ']' : + '[' + partial.join(',') + ']'; + gap = mind; + return v; + } + +// If the replacer is an array, use it to select the members to be stringified. + + if (rep && typeof rep === 'object') { + length = rep.length; + for (i = 0; i < length; i += 1) { + k = rep[i]; + if (typeof k === 'string') { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } else { + +// Otherwise, iterate through all of the keys in the object. + + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = str(k, value); + if (v) { + partial.push(quote(k) + (gap ? ': ' : ':') + v); + } + } + } + } + +// Join all of the member texts together, separated with commas, +// and wrap them in braces. + + v = partial.length === 0 ? '{}' : + gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + + mind + '}' : '{' + partial.join(',') + '}'; + gap = mind; + return v; + } + } + +// If the JSON object does not yet have a stringify method, give it one. + + if (typeof JSON.stringify !== 'function') { + JSON.stringify = function (value, replacer, space) { + +// The stringify method takes a value and an optional replacer, and an optional +// space parameter, and returns a JSON text. The replacer can be a function +// that can replace values, or an array of strings that will select the keys. +// A default replacer method can be provided. Use of the space parameter can +// produce text that is more easily readable. + + var i; + gap = ''; + indent = ''; + +// If the space parameter is a number, make an indent string containing that +// many spaces. + + if (typeof space === 'number') { + for (i = 0; i < space; i += 1) { + indent += ' '; + } + +// If the space parameter is a string, it will be used as the indent string. + + } else if (typeof space === 'string') { + indent = space; + } + +// If there is a replacer, it must be a function or an array. +// Otherwise, throw an error. + + rep = replacer; + if (replacer && typeof replacer !== 'function' && + (typeof replacer !== 'object' || + typeof replacer.length !== 'number')) { + throw new Error('JSON.stringify'); + } + +// Make a fake root object containing our value under the key of ''. +// Return the result of stringifying the value. + + return str('', {'': value}); + }; + } + + +// If the JSON object does not yet have a parse method, give it one. + + if (typeof JSON.parse !== 'function') { + JSON.parse = function (text, reviver) { + +// The parse method takes a text and an optional reviver function, and returns +// a JavaScript value if the text is a valid JSON text. + + var j; + + function walk(holder, key) { + +// The walk method is used to recursively walk the resulting structure so +// that modifications can be made. + + var k, v, value = holder[key]; + if (value && typeof value === 'object') { + for (k in value) { + if (Object.hasOwnProperty.call(value, k)) { + v = walk(value, k); + if (v !== undefined) { + value[k] = v; + } else { + delete value[k]; + } + } + } + } + return reviver.call(holder, key, value); + } + + +// Parsing happens in four stages. In the first stage, we replace certain +// Unicode characters with escape sequences. JavaScript handles many characters +// incorrectly, either silently deleting them, or treating them as line endings. + + cx.lastIndex = 0; + if (cx.test(text)) { + text = text.replace(cx, function (a) { + return '\\u' + + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + +// In the second stage, we run the text against regular expressions that look +// for non-JSON patterns. We are especially concerned with '()' and 'new' +// because they can cause invocation, and '=' because it can cause mutation. +// But just to be safe, we want to reject all unexpected forms. + +// We split the second stage into 4 regexp operations in order to work around +// crippling inefficiencies in IE's and Safari's regexp engines. First we +// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we +// replace all simple value tokens with ']' characters. Third, we delete all +// open brackets that follow a colon or comma or that begin the text. Finally, +// we look to see that the remaining characters are only whitespace or ']' or +// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval. + + if (/^[\],:{}\s]*$/. +test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'). +replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'). +replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) { + +// In the third stage we use the eval function to compile the text into a +// JavaScript structure. The '{' operator is subject to a syntactic ambiguity +// in JavaScript: it can begin a block or an object literal. We wrap the text +// in parens to eliminate the ambiguity. + + j = eval('(' + text + ')'); + +// In the optional fourth stage, we recursively walk the new structure, passing +// each name/value pair to a reviver function for possible transformation. + + return typeof reviver === 'function' ? + walk({'': j}, '') : j; + } + +// If the text is not JSON parseable, then a SyntaxError is thrown. + + throw new SyntaxError('JSON.parse'); + }; + } +}()); |