diff --git a/amd/build/clientrender.min.js b/amd/build/clientrender.min.js index d26913e..957d865 100644 --- a/amd/build/clientrender.min.js +++ b/amd/build/clientrender.min.js @@ -5,6 +5,6 @@ * @copyright 2026 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define("filter_oembed/clientrender",["jquery","core/log"],(function($,Log){return{init:function(){$(".oembed-client-render").each((function(){var $container=$(this);if(!$container.data("processed")){$container.data("processed",!0);var oembedUrl=$container.data("oembed-url"),originalUrl=$container.data("original-url"),params=$container.data("params");if(!oembedUrl)return Log.debug("filter_oembed/clientrender: No oembed URL provided"),void $container.html(''+originalUrl+"");$.ajax({url:oembedUrl,dataType:"json",success:function(data){if(data&&data.html){var embed=data.html;if(params){var paramStr="";for(var key in params)params.hasOwnProperty(key)&&(paramStr+="&"+key+"="+encodeURIComponent(params[key]));embed=embed.replace("?feature=oembed","?feature=oembed"+paramStr)}var aspectRatio=0;if(data.width&&data.height&&(aspectRatio=data.height/data.width),aspectRatio>0){var paddiv='
';$container.html('
'+embed+paddiv+"
")}else $container.html('
'+embed+"
")}else Log.debug("filter_oembed/clientrender: No HTML in oembed response for "+originalUrl),$container.html(''+originalUrl+"")},error:function(jqXHR,textStatus,errorThrown){Log.debug("filter_oembed/clientrender: Error loading oembed content for "+originalUrl+" - "+textStatus+": "+errorThrown),$container.html(''+originalUrl+"")}})}}))}}})); +define("filter_oembed/clientrender",["jquery","core/log"],(function($,Log){return{init:function(){$(".oembed-client-render").each((function(){var $container=$(this);if(!$container.data("processed")){$container.data("processed",!0);var oembedUrl=$container.data("oembed-url"),originalUrl=$container.data("original-url"),params=$container.data("params"),withCredentials=1===$container.data("with-credentials");if(!oembedUrl)return Log.debug("filter_oembed/clientrender: No oembed URL provided"),void $container.html(''+originalUrl+"");$.ajax({url:oembedUrl,dataType:"json",xhrFields:{withCredentials:withCredentials},success:function(data){if(data&&data.html){var embed=data.html;if(params){var paramStr="";for(var key in params)params.hasOwnProperty(key)&&(paramStr+="&"+key+"="+encodeURIComponent(params[key]));embed=embed.replace("?feature=oembed","?feature=oembed"+paramStr)}var aspectRatio=0;if(data.width&&data.height&&(aspectRatio=data.height/data.width),aspectRatio>0){var paddiv='
';$container.html('
'+embed+paddiv+"
")}else $container.html('
'+embed+"
")}else Log.debug("filter_oembed/clientrender: No HTML in oembed response for "+originalUrl),$container.html(''+originalUrl+"")},error:function(jqXHR,textStatus,errorThrown){Log.debug("filter_oembed/clientrender: Error loading oembed content for "+originalUrl+" - "+textStatus+": "+errorThrown),$container.html(''+originalUrl+"")}})}}))}}})); //# sourceMappingURL=clientrender.min.js.map \ No newline at end of file diff --git a/amd/src/clientrender.js b/amd/src/clientrender.js index cdaf701..f94a203 100644 --- a/amd/src/clientrender.js +++ b/amd/src/clientrender.js @@ -29,29 +29,33 @@ define(['jquery', 'core/log'], function($, Log) { var init = function() { $('.oembed-client-render').each(function() { var $container = $(this); - + if ($container.data('processed')) { return; } $container.data('processed', true); - + var oembedUrl = $container.data('oembed-url'); var originalUrl = $container.data('original-url'); var params = $container.data('params'); - + var withCredentials = $container.data('with-credentials') === 1; + if (!oembedUrl) { Log.debug('filter_oembed/clientrender: No oembed URL provided'); $container.html('' + originalUrl + ''); return; } - + $.ajax({ url: oembedUrl, dataType: 'json', + xhrFields: { + withCredentials: withCredentials + }, success: function(data) { if (data && data.html) { var embed = data.html; - + if (params) { var paramStr = ''; for (var key in params) { @@ -61,12 +65,12 @@ define(['jquery', 'core/log'], function($, Log) { } embed = embed.replace('?feature=oembed', '?feature=oembed' + paramStr); } - + var aspectRatio = 0; if (data.width && data.height) { aspectRatio = data.height / data.width; } - + if (aspectRatio > 0) { var padding = aspectRatio * 100; var paddiv = '
'; @@ -80,7 +84,7 @@ define(['jquery', 'core/log'], function($, Log) { } }, error: function(jqXHR, textStatus, errorThrown) { - Log.debug('filter_oembed/clientrender: Error loading oembed content for ' + originalUrl + + Log.debug('filter_oembed/clientrender: Error loading oembed content for ' + originalUrl + ' - ' + textStatus + ': ' + errorThrown); $container.html('' + originalUrl + ''); } diff --git a/classes/db/providerrow.php b/classes/db/providerrow.php index 1bdef31..d2d6f41 100644 --- a/classes/db/providerrow.php +++ b/classes/db/providerrow.php @@ -64,6 +64,11 @@ class providerrow extends abstract_dbrow { */ public $rendermode; + /** + * @var bool include credentials in client-side requests + */ + public $withcredentials; + /** * @var int time created */ diff --git a/classes/forms/provider.php b/classes/forms/provider.php index bf218a8..7183816 100644 --- a/classes/forms/provider.php +++ b/classes/forms/provider.php @@ -48,6 +48,7 @@ public function definition() { 'endpoints' => ['required' => true, 'type' => 'textarea', 'paramtype' => PARAM_TEXT], 'enabled' => ['required' => false, 'type' => 'checkbox', 'paramtype' => PARAM_INT], 'rendermode' => ['required' => false, 'type' => 'select', 'paramtype' => PARAM_TEXT], + 'withcredentials' => ['required' => false, 'type' => 'checkbox', 'paramtype' => PARAM_INT], 'source' => ['required' => true, 'type' => 'hidden', 'paramtype' => PARAM_TEXT], ]; diff --git a/classes/provider/provider.php b/classes/provider/provider.php index 914728c..5f2cbe1 100644 --- a/classes/provider/provider.php +++ b/classes/provider/provider.php @@ -70,6 +70,11 @@ class provider { */ protected $rendermode = 'server'; + /** + * @var bool include credentials in client-side requests + */ + protected $withcredentials = 0; + /** * @var Class constant descriptio for local. */ @@ -116,6 +121,7 @@ public function __construct($data = null) { $this->source = isset($data['source']) ? $data['source'] : ''; $this->rendermode = isset($data['rendermode']) ? $data['rendermode'] : 'server'; + $this->withcredentials = isset($data['withcredentials']) ? $data['withcredentials'] : 0; } } @@ -254,7 +260,7 @@ protected function endpoints_regex(endpoint $endpoint) { * @throws \coding_exception */ public function __get($name) { - $allowed = ['id', 'enabled', 'providername', 'providerurl', 'endpoints', 'source', 'rendermode']; + $allowed = ['id', 'enabled', 'providername', 'providerurl', 'endpoints', 'source', 'rendermode', 'withcredentials']; if (in_array($name, $allowed)) { return $this->$name; } else { @@ -262,6 +268,17 @@ public function __get($name) { } } + /** + * Magic method for isset() checks on accessible properties. + * Required so that empty() works correctly with __get() properties. + * @param string $name + * @return bool + */ + public function __isset($name) { + $allowed = ['id', 'enabled', 'providername', 'providerurl', 'endpoints', 'source', 'rendermode', 'withcredentials']; + return in_array($name, $allowed) && isset($this->$name); + } + /** * Set enabled? * @param boolean $enabled diff --git a/classes/service/oembed.php b/classes/service/oembed.php index 6a997dc..f3027fd 100755 --- a/classes/service/oembed.php +++ b/classes/service/oembed.php @@ -149,7 +149,7 @@ public function html_output($text) { // Check if this provider uses client-side rendering. if ($provider->rendermode === 'client') { $PAGE->requires->js_call_amd('filter_oembed/clientrender', 'init'); - $output = $this->oembed_getclienthtml($requesturl, $text, $params); + $output = $this->oembed_getclienthtml($provider, $requesturl, $text, $params); } else { // Server-side rendering. $jsonret = $provider->oembed_response($requesturl); @@ -170,17 +170,20 @@ public function html_output($text) { /** * Get client-side rendering placeholder html. * + * @param provider $provider The provider used for this embed. * @param string $requesturl The oembed request URL. * @param string $originalurl The original URL being embedded. * @param array $params Additional URL parameters. * @return string */ - protected function oembed_getclienthtml($requesturl, $originalurl, $params = []) { + protected function oembed_getclienthtml(provider $provider, $requesturl, $originalurl, $params = []) { $paramsdata = !empty($params) ? htmlspecialchars(json_encode($params), ENT_QUOTES, 'UTF-8') : ''; + $withcredentials = (bool)$provider->withcredentials; $output = '
' . + ($paramsdata ? 'data-params="' . $paramsdata . '" ' : '') . + 'data-with-credentials="' . ($withcredentials ? '1' : '0') . '">' . '
Loading...
' . '
'; return $output; diff --git a/db/install.xml b/db/install.xml index eaefc19..2255dc2 100644 --- a/db/install.xml +++ b/db/install.xml @@ -1,5 +1,5 @@ - @@ -13,6 +13,7 @@ + diff --git a/db/upgrade.php b/db/upgrade.php index 364fdf8..884e5b7 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -156,5 +156,19 @@ function xmldb_filter_oembed_upgrade($oldversion) { upgrade_plugin_savepoint(true, 2026031300, 'filter', 'oembed'); } + if ($oldversion < 2026031301) { + // Define field withcredentials to be added to filter_oembed. + $table = new xmldb_table('filter_oembed'); + $field = new xmldb_field('withcredentials', XMLDB_TYPE_INTEGER, '1', null, null, null, '0', 'rendermode'); + + // Conditionally launch add field withcredentials. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Oembed savepoint reached. + upgrade_plugin_savepoint(true, 2026031301, 'filter', 'oembed'); + } + return true; } diff --git a/lang/en/filter_oembed.php b/lang/en/filter_oembed.php index cee684b..f8023c6 100644 --- a/lang/en/filter_oembed.php +++ b/lang/en/filter_oembed.php @@ -69,3 +69,4 @@ $string['targettag'] = 'Target tag'; $string['targettag_desc'] = 'What tag type should be filtered - anchors or divs with the oEmbed class.'; $string['updateproviders'] = 'Update oEmbed provider information.'; +$string['withcredentials'] = 'Include credentials in client-side requests. Only valid for client side embeds.'; diff --git a/lib.php b/lib.php index a9657c9..eb79dd5 100644 --- a/lib.php +++ b/lib.php @@ -60,6 +60,7 @@ function filter_oembed_output_fragment_provider($args) { 'endpoints' => '', 'enabled' => 1, 'rendermode' => 'server', + 'withcredentials' => 0, 'source' => 'local::new', ]; } else { @@ -71,9 +72,15 @@ function filter_oembed_output_fragment_provider($args) { } } + if (!is_array($ajaxdata)) { + $ajaxdata = []; + } if (!isset($ajaxdata['enabled'])) { $ajaxdata['enabled'] = 0; } + if (!isset($ajaxdata['withcredentials'])) { + $ajaxdata['withcredentials'] = 0; + } $actionurl = $CFG->wwwroot . '/filter/oembed/manageproviders.php'; // Pass the source type as custom data so it can by used to detetmine the type of edit. $form = new provider( diff --git a/templates/.mustachelintignore b/templates/.mustachelintignore new file mode 100644 index 0000000..abb49fa --- /dev/null +++ b/templates/.mustachelintignore @@ -0,0 +1,2 @@ +# Templates that are table row partials and cannot be validated in isolation. +managementpagerow.mustache diff --git a/version.php b/version.php index 083e3f5..1306ec9 100644 --- a/version.php +++ b/version.php @@ -26,8 +26,8 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2026031300; +$plugin->version = 2026031301; $plugin->requires = 2019111800; $plugin->component = 'filter_oembed'; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '3.8.0 (Build - 2026031300)'; +$plugin->release = '3.8.0 (Build - 2026031301)';