diff --git a/docs/guides/javascript.rst b/docs/guides/javascript.rst index 0b324e3dc27..57f50002365 100644 --- a/docs/guides/javascript.rst +++ b/docs/guides/javascript.rst @@ -542,6 +542,66 @@ Plugins that load a widget layout via Ajax should initialize via this module: widgets.init(); }); +Module ``elgg/lightbox`` +------------------------ + +Elgg is distributed with the Colorbox jQuery library. Please go to http://www.jacklmoore.com/colorbox for more information on the options of this lightbox. + +Use the following classes to bind your anchor elements to a lightbox: + + * ``elgg-lightbox`` - loads an HTML resource + * ``elgg-lightbox-photo`` - loads an image resource (should be used to avoid displaying raw image bytes instead of an ``img`` tag) + * ``elgg-lightbox-inline`` - displays an inline HTML element in a lightbox + * ``elgg-lightbox-iframe`` - loads a resource in an ``iframe`` + +You may apply colorbox options to an individual ``elgg-lightbox`` element by setting the attribute ``data-colorbox-opts`` to a JSON settings object. + +.. code:: php + + echo elgg_view('output/url', [ + 'text' => 'Open lightbox', + 'href' => 'ajax/view/my_view', + 'class' => 'elgg-lightbox', + 'data-colorbox-opts' => json_encode([ + 'width' => '300px', + ]) + ]); + +Use ``"getOptions", "ui.lightbox"`` plugin hook to filter options passed to ``$.colorbox()`` whenever a lightbox is opened. Note that the hook handler should depend on ``elgg/init`` AMD module. + +``elgg/lightbox`` AMD module should be used to open and close the lightbox programmatically: + +.. code:: js + + define(function(require) { + var lightbox = require('elgg/lightbox'); + var spinner = require('elgg/spinner'); + + lightbox.open({ + html: '

Hello world!

', + onClosed: function() { + lightbox.open({ + onLoad: spinner.start, + onComplete: spinner.stop, + photo: true, + href: 'https://elgg.org/cache/1457904417/default/community_theme/graphics/logo.png', + }); + } + }); + }); + +To support gallery sets (via ``rel`` attribute), you need to bind colorbox directly to a specific selector (note that this will ignore ``data-colorbox-opts`` on all elements in a set): + +.. code:: js + + require(['elgg/lightbox'], function(lightbox) { + var options = { + photo: true, + width: 500 + }; + lightbox.bind('a[rel="my-gallery"]', options, false); // 3rd attribute ensures binding is done without proxies + }); + Traditional scripts =================== @@ -639,6 +699,9 @@ Available hooks **getOptions, ui.popup** This hook is fired for pop up displays (``"rel"="popup"``) and allows for customized placement options. +**getOptions, ui.lightbox** + This hook can be used to filter options passed to ``$.colorbox()`` + **config, ckeditor** This filters the CKEditor config object. Register for this hook in a plugin boot module. The defaults can be seen in the module ``elgg/ckeditor/config``. diff --git a/docs/guides/upgrading.rst b/docs/guides/upgrading.rst index 754124ea872..e3afd19c558 100644 --- a/docs/guides/upgrading.rst +++ b/docs/guides/upgrading.rst @@ -17,17 +17,25 @@ Deprecated APIs * ``elgg.ui.river`` JavaScript library: Remove calls to ``elgg_load_js('elgg.ui.river')`` from plugin code. Update ``core/river/filter`` and ``forms/comment/save``, if overwritten, to require component AMD modules * ``elgg.ui.popupOpen()`` and ``elgg.ui.popupClose()`` methods in ``elgg.ui`` JS library: Use ``elgg/popup`` module instead. + * ``lightbox.js`` library: Do not use ``elgg_load_js('lightbox.js');`` unless your code references deprecated ``elgg.ui.lightbox`` namespace. Use ``elgg/lightbox`` AMD module instead. + * ``lightbox.css`` library: Lightbox CSS now extends ``elgg.css``. Calls to ``elgg_require_css('lightbox.css')`` have no effect. Deprecated Views ---------------- * ``elgg/ui.river.js`` is deprecated: Do not rely on simplecache URLs to work. + * ``lightbox/settings.js`` is deprecated: Use ``getOptions, ui.lightbox`` JS plugin hook or ``data-colorbox-opts`` attribute. Added ``elgg/popup`` module ----------------------------- New :doc:`elgg/popup module ` can be used to build out more complex trigger-popup interactions, including binding custom anchor types and opening/closing popups programmatically. +Added ``elgg/lightbox`` module +------------------------------ + +New :doc:`elgg/lightbox module ` can be used to open and close the lightbox programmatically. + From 2.0 to 2.1 =============== diff --git a/engine/lib/views.php b/engine/lib/views.php index 6e9386761cf..8ebd5ce852e 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1688,9 +1688,10 @@ function elgg_views_boot() { elgg_register_simplecache_view('elgg/init.js'); - // optional stuff + elgg_extend_view('elgg.css', 'colorbox.css'); + + // provide warning to use elgg/lightbox AMD elgg_register_js('lightbox', elgg_get_simplecache_url('lightbox.js')); - elgg_register_css('lightbox', elgg_get_simplecache_url('lightbox/elgg-colorbox-theme/colorbox.css')); // just provides warning to use elgg/autocomplete AMD elgg_register_js('elgg.autocomplete', elgg_normalize_url('js/lib/ui.autocomplete.js')); diff --git a/engine/views.php b/engine/views.php index bebe6873af7..1dbcccc2eff 100644 --- a/engine/views.php +++ b/engine/views.php @@ -42,5 +42,8 @@ "jquery.jeditable.js" => dirname(__DIR__) . "/bower_components/jquery-jeditable/jquery.jeditable.js", "jquery.ui.autocomplete.html.js" => dirname(__DIR__) . "/bower_components/jquery-ui-extensions/src/autocomplete/jquery.ui.autocomplete.html.js", "sprintf.js" => dirname(__DIR__) . "/bower_components/sprintf/src/sprintf.js", + + 'colorbox.css' => dirname(__DIR__) . "/views/default/lightbox/elgg-colorbox-theme/colorbox.css", + 'colorbox-images/' => dirname(__DIR__) . "/views/default/lightbox/elgg-colorbox-theme/colorbox-images/", ], ]; diff --git a/js/lib/elgglib.js b/js/lib/elgglib.js index 14625eab90b..e90552b88bf 100644 --- a/js/lib/elgglib.js +++ b/js/lib/elgglib.js @@ -403,7 +403,7 @@ elgg.register_error = function(errors, delay) { /** * Logs a notice about use of a deprecated function or capability * @param {String} msg The deprecation message to display - * @param {Number} dep_version The version the function was deprecated for + * @param {String} dep_version The version the function was deprecated for * @since 1.9 */ elgg.deprecated_notice = function(msg, dep_version) { diff --git a/mod/developers/start.php b/mod/developers/start.php index 0a99e838272..c1d3452f109 100644 --- a/mod/developers/start.php +++ b/mod/developers/start.php @@ -68,8 +68,6 @@ function developers_process_settings() { if (!empty($settings['show_gear']) && elgg_is_admin_logged_in() && !elgg_in_context('admin')) { elgg_require_js('elgg/dev/gear'); - elgg_load_js('lightbox'); - elgg_load_css('lightbox'); elgg_register_ajax_view('developers/gear_popup'); elgg_register_simplecache_view('elgg/dev/gear.html'); diff --git a/mod/developers/views/default/elgg/dev/gear.js b/mod/developers/views/default/elgg/dev/gear.js index a6d17ebb248..90cc6a5c7bb 100644 --- a/mod/developers/views/default/elgg/dev/gear.js +++ b/mod/developers/views/default/elgg/dev/gear.js @@ -6,6 +6,7 @@ define(function (require) { var elgg = require('elgg'); var spinner = require('elgg/spinner'); var gear_html = require('text!elgg/dev/gear.html'); + require('elgg/lightbox'); $(gear_html) .appendTo('body') diff --git a/mod/developers/views/default/theme_sandbox/javascript/lightbox.js b/mod/developers/views/default/theme_sandbox/javascript/lightbox.js new file mode 100644 index 00000000000..cb5dbf79bc1 --- /dev/null +++ b/mod/developers/views/default/theme_sandbox/javascript/lightbox.js @@ -0,0 +1,8 @@ +define(function(require) { + var lightbox = require('elgg/lightbox'); + var opts = { + photo: true, + width: 600 + }; + lightbox.bind('[rel="lightbox-gallery"]', opts, false); +}); \ No newline at end of file diff --git a/mod/developers/views/default/theme_sandbox/javascript/lightbox.php b/mod/developers/views/default/theme_sandbox/javascript/lightbox.php index 1832e730466..2abbd724ff9 100644 --- a/mod/developers/views/default/theme_sandbox/javascript/lightbox.php +++ b/mod/developers/views/default/theme_sandbox/javascript/lightbox.php @@ -1,12 +1,72 @@ 'Open lighbox', 'href' => "ajax/view/developers/ajax", 'class' => 'elgg-lightbox' )); -echo $link; +echo elgg_view('output/url', array( + 'text' => 'Open iframe lightbox', + 'href' => 'https://elgg.org', + 'class' => 'elgg-lightbox-iframe mll', + 'data-colorbox-opts' => json_encode([ + 'width' => '80%', + 'height' => '80%', + ]), +)); + +echo elgg_view('output/url', array( + 'text' => 'Open inline HTML lightbox', + 'href' => '#lightbox-inline', + 'class' => 'elgg-lightbox-inline mll', +)); +?> + + 'object', + 'subtypes' => 'file', + 'metadata_name_value_paris' => [ + 'name' => 'simpletype', + 'value' => 'image', + ], + )); + +if (!$files) { + return; +} + +elgg_require_js('theme_sandbox/javascript/lightbox'); + +echo elgg_view('output/url', array( + 'text' => 'Open photo lightbox', + 'href' => elgg_get_download_url($files[0]), + 'class' => 'elgg-lightbox-photo mll', +)); +?> + + diff --git a/mod/embed/start.php b/mod/embed/start.php index 160f8388ce6..67673bc1ee0 100644 --- a/mod/embed/start.php +++ b/mod/embed/start.php @@ -49,8 +49,6 @@ function embed_longtext_menu($hook, $type, $items, $vars) { $url = 'embed?container_guid=' . $page_owner->getGUID(); } - elgg_load_js('lightbox'); - elgg_load_css('lightbox'); elgg_require_js('jquery.form'); elgg_load_js('elgg.embed'); diff --git a/mod/embed/views/default/embed/embed.js.php b/mod/embed/views/default/embed/embed.js.php index f6326d9d45e..a3b7b4e8439 100644 --- a/mod/embed/views/default/embed/embed.js.php +++ b/mod/embed/views/default/embed/embed.js.php @@ -91,7 +91,9 @@ textArea.val(result); } - elgg.ui.lightbox.close(); + require(['elgg/lightbox'], function(lightbox) { + lightbox.close(); + }); event.preventDefault(); }; diff --git a/mod/file/views/default/file/specialcontent/image/default.php b/mod/file/views/default/file/specialcontent/image/default.php index 7037d600973..4cc852f6ded 100644 --- a/mod/file/views/default/file/specialcontent/image/default.php +++ b/mod/file/views/default/file/specialcontent/image/default.php @@ -12,8 +12,6 @@ $download_url = elgg_get_download_url($file); if ($vars['full_view']) { - elgg_load_js('lightbox'); - elgg_load_css('lightbox'); echo << diff --git a/mod/likes/views/default/likes/count.php b/mod/likes/views/default/likes/count.php index 2105b8d44a3..a45f90b8d26 100644 --- a/mod/likes/views/default/likes/count.php +++ b/mod/likes/views/default/likes/count.php @@ -8,9 +8,6 @@ $num_of_likes = \Elgg\Likes\DataService::instance()->getNumLikes($vars['entity']); $guid = $vars['entity']->guid; -elgg_load_js('lightbox'); -elgg_load_css('lightbox'); - // display the number of likes if ($num_of_likes == 1) { $likes_string = elgg_echo('likes:userlikedthis', array($num_of_likes)); diff --git a/mod/reportedcontent/views/default/elgg/reportedcontent.js b/mod/reportedcontent/views/default/elgg/reportedcontent.js index e5f6848a542..ceb2e1700d5 100644 --- a/mod/reportedcontent/views/default/elgg/reportedcontent.js +++ b/mod/reportedcontent/views/default/elgg/reportedcontent.js @@ -16,7 +16,9 @@ define(function (require) { data: $form.serialize(), success: function (data) { if (data.status == 0) { - elgg.ui.lightbox.close(); + require(['elgg/lightbox'], function(lightbox) { + lightbox.close(); + }); } } }); @@ -24,7 +26,9 @@ define(function (require) { $(document).on('click', '.elgg-form-reportedcontent-add .elgg-button-cancel', function (e) { if ($(this).is('#colorbox *')) { - elgg.ui.lightbox.close(); + require(['elgg/lightbox'], function(lightbox) { + lightbox.close(); + }); } else { if (history.length > 1) { history.go(-1); diff --git a/views/default/admin/plugins.php b/views/default/admin/plugins.php index f18b1601e8b..0cbcb558d82 100644 --- a/views/default/admin/plugins.php +++ b/views/default/admin/plugins.php @@ -8,9 +8,6 @@ * @subpackage Admin.Plugins */ -elgg_load_js('lightbox'); -elgg_load_css('lightbox'); - // @todo this should occur in the controller code _elgg_generate_plugin_entities(); diff --git a/views/default/elgg.js.php b/views/default/elgg.js.php index 18cff3995e4..84e9bd97b2c 100644 --- a/views/default/elgg.js.php +++ b/views/default/elgg.js.php @@ -2,8 +2,6 @@ /** * Core Elgg JavaScript file */ - -use Elgg\Filesystem\Directory; global $CONFIG; @@ -25,9 +23,10 @@ // @todo: remove in 3.x and use async calls echo elgg_view('elgg/widgets.js'); -// We use a named AMD module and inine it here in order to save HTTP requests, -// as this module will be required on each page +// We use named AMD modules and inine them here in order to save HTTP requests, +// as these modules will be required on each page echo elgg_view('elgg/popup.js'); +echo elgg_view('elgg/lightbox.js'); $elggDir = \Elgg\Application::elggDir(); $files = array( @@ -110,4 +109,21 @@ elgg.trigger_hook('boot', 'system'); -require(['elgg/init', 'elgg/ready']); \ No newline at end of file +require(['elgg/init', 'elgg/ready']); + + + require(['elgg'], function(elgg) { + elgg.provide('elgg.ui.lightbox'); + + }); + + +// we inline this in 2.x because both elgg/lightbox and the legacy lightbox.js library use it +// and legacy code assumes that lightbox.js loads the library synchronously. + diff --git a/views/default/elgg/lightbox.js b/views/default/elgg/lightbox.js new file mode 100644 index 00000000000..b2a231d970c --- /dev/null +++ b/views/default/elgg/lightbox.js @@ -0,0 +1,126 @@ +/** + * Lightbox module + * We use a named module and inline it in elgg.js. This allows us to deprecate the old + * elgg.ui.lightbox library. + * + * @module elgg/lightbox + */ +define('elgg/lightbox', function (require) { + + var elgg = require('elgg'); + var $ = require('jquery'); + require('elgg/init'); + // TODO in 3.0 depend on "jquery.colorbox" + + var lightbox = { + + /** + * Returns lightbox settings + * + * @param {Object} opts Additional options + * @return {Object} + */ + getOptions: function (opts) { + if (!$.isPlainObject(opts)) { + opts = {}; + } + + // Note: keep these in sync with /views/default/lightbox.js.php + var settings = { + current: elgg.echo('js:lightbox:current', ['{current}', '{total}']), + previous: elgg.echo('previous'), + next: elgg.echo('next'), + close: elgg.echo('close'), + xhrError: elgg.echo('error:default'), + imgError: elgg.echo('error:default'), + opacity: 0.5, + maxWidth: '100%', + // don't move colorbox on small viewports https://github.com/Elgg/Elgg/issues/5312 + reposition: $(window).height() > 600 + }; + + elgg.provide('elgg.ui.lightbox'); + + if ($.isPlainObject(elgg.ui.lightbox.deprecated_settings)) { + $.extend(settings, elgg.ui.lightbox.deprecated_settings, opts); + } else { + $.extend(settings, opts); + } + + return elgg.trigger_hook('getOptions', 'ui.lightbox', null, settings); + }, + + /** + * Bind colorbox lightbox click to HTML + * + * @param {Object} selector CSS selector matching colorbox openers + * @param {Object} opts Colorbox options. These are overridden by data-colorbox-opts options + * @param {Boolean} use_element_data If set to false, selector will be bound directly as `$(selector).colorbox()` + * @return void + */ + bind: function (selector, opts, use_element_data) { + if (!$.isPlainObject(opts)) { + opts = {}; + } + + //console.log(use_element_data); + + // Allow direct binding to allow grouping by rel attribute + if (use_element_data === false) { + $(selector).colorbox(lightbox.getOptions(opts)); + return; + } + + $(document) + .off('click.lightbox', selector) + .on('click.lightbox', selector, function (e) { + e.preventDefault(); + var $this = $(this), + href = $this.prop('href') || $this.prop('src'), + // Note: data-colorbox was reserved https://github.com/jackmoore/colorbox/issues/435 + dataOpts = $this.data('colorboxOpts'); + + if (!$.isPlainObject(dataOpts)) { + dataOpts = {}; + } + + if (!dataOpts.href && href) { + dataOpts.href = href; + } + + // merge data- options into opts + $.extend(opts, dataOpts); + if (opts.inline && opts.href) { + opts.href = elgg.getSelectorFromUrlFragment(opts.href); + } + + lightbox.open(opts); + }); + }, + + /** + * Open the colorbox + * + * @param {object} opts Colorbox options + * @return void + */ + open: function (opts) { + $.colorbox(lightbox.getOptions(opts)); + }, + + /** + * Close the colorbox + * @return void + */ + close: function () { + $.colorbox.close(); + } + }; + + lightbox.bind(".elgg-lightbox"); + lightbox.bind(".elgg-lightbox-photo", {photo: true}); + lightbox.bind(".elgg-lightbox-inline", {inline: true}); + lightbox.bind(".elgg-lightbox-iframe", {iframe: true}); + + return lightbox; +}); \ No newline at end of file diff --git a/views/default/lightbox.js.php b/views/default/lightbox.js.php index fcf9a8dbbe8..b0458259ac0 100644 --- a/views/default/lightbox.js.php +++ b/views/default/lightbox.js.php @@ -2,23 +2,16 @@ /** * Elgg lightbox * - * Usage - * --------------- - * Call elgg_load_js('lightbox') and elgg_load_css('lightbox'). - * Then apply the class elgg-lightbox to links. - * - * - * Advanced Usage - * ----------------- * Elgg is distributed with the Colorbox jQuery library. Please go to * http://www.jacklmoore.com/colorbox for more information on the options of this lightbox. * - * You can change global options by overriding the js/lightbox/settings view. + * Use .elgg-lightbox or .elgg-lightbox-photo class on your anchor element to + * bind it to a lightbox. * * You may apply colorbox options to an individual .elgg-lightbox element - * by setting the attribute data-colorbox-opts to a JSON settings object. You - * can also set options in the elgg.ui.lightbox.bind() method, but data - * attributes will take precedence. + * by setting the attribute data-colorbox-opts to a JSON settings object. + * You can use "getOptions", "ui.lightbox" plugin hook to filter options before + * they are passed to $.colorbox(). * * To support a hidden div as the source, add "inline: true" as a * data-colorbox-opts option. For example, using the output/url view, add: @@ -29,30 +22,104 @@ * ------------------------------------- * In a plugin, override this view and override the registration for the * lightbox JavaScript and CSS (@see elgg_views_boot()). + * + * @deprecated 2.2 */ - ?> //