Skip to content

Commit

Permalink
#4695 - Embeds improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
romanlesnikov committed Apr 19, 2024
1 parent 68c274d commit 682b583
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 52 deletions.
6 changes: 4 additions & 2 deletions api.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@

bx_api_check_access();

if (bx_get('cnf') ){
echo getParam('sys_api_config');
if (bx_get('cnf') ){
$sCnf = getParam('sys_api_config');
echo json_encode(['data' => $sCnf, 'hash' => md5($sCnf)]);
exit();
}

Expand Down Expand Up @@ -98,6 +99,7 @@
'method' => $sMethod,
'params' => $aParams,
'data' => $mixedRet,
'hash' => md5(getParam('sys_api_config')),
];

echo json_encode($aRv);
5 changes: 5 additions & 0 deletions inc/classes/BxDolEmbed.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ public function getData ($sUrl, $sTheme)
$aData = json_decode($sData, true);
return $aData;
}

public function getHtml ($sUrl, $sTheme)
{
// override this function in particular editor class
}
}

/** @} */
45 changes: 40 additions & 5 deletions inc/utils.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -1188,17 +1188,27 @@ function bx_get_site_info_fix_relative_url ($sSourceUrl, $s)

function bx_parse_html_tag ($sContent, $sTag, $sAttrNameName, $sAttrNameValue, $sAttrContentName, $sCharset = false, $bSpecialCharsDecode = true)
{
if (!preg_match("/<{$sTag}\s+{$sAttrNameName}[='\" ]+{$sAttrNameValue}['\"]\s+{$sAttrContentName}[='\" ]+([^'>\"]*)['\"][^>]*>/i", $sContent, $aMatch) || !isset($aMatch[1]))
preg_match("/<{$sTag}\s+{$sAttrContentName}[='\" ]+([^'>\"]*)['\"]\s+{$sAttrNameName}[='\" ]+{$sAttrNameValue}['\"][^>]*>/i", $sContent, $aMatch);
// This regex is designed to be more flexible with attribute orders and spacing
$regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?\s+[^>]*{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"][^>]*>/i";
if (!preg_match($regex, $sContent, $aMatch)) {
// Try reversing the attribute order in case the first regex fails
$regex = "/<{$sTag}\s+(?:[^>]*?\s+)?{$sAttrContentName}\s*=\s*['\"]([^'\"]*)['\"]\s+[^>]*{$sAttrNameName}\s*=\s*['\"]?{$sAttrNameValue}['\"]?[^>]*>/i";
preg_match($regex, $sContent, $aMatch);
}

// Extract the attribute content if available
$s = isset($aMatch[1]) ? $aMatch[1] : '';

if ($s && $sCharset)
// Optionally convert character encoding
if ($s && $sCharset) {
$s = mb_convert_encoding($s, 'UTF-8', $sCharset);
}

if ($bSpecialCharsDecode)
// Optionally decode special HTML characters
if ($bSpecialCharsDecode) {
$s = htmlspecialchars_decode($s);

}

return $s;
}

Expand Down Expand Up @@ -2153,6 +2163,31 @@ function bx_linkify($text, $sAttrs = '', $bHtmlSpecialChars = false)
return $text;
}

function bx_linkify_embeded($text)
{
$urlRegex = '/\b((https?:\/\/)|(www\.))((([0-9a-zA-Z_!~*\'().&=+$%-]+:)?[0-9a-zA-Z_!~*\'().&=+$%-]+@)?(([0-9]{1,3}\.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*\'()-]+\.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z]\.[a-zA-Z]{2,16})(:[0-9]{1,4})?((\/[0-9a-zA-Z_!~*\'().;?:@&=+$,%#-]*)*))/';
preg_match_all($urlRegex, $text, $matches, PREG_SET_ORDER);

// Reverse the matches to mimic JavaScript's reverse order processing
$matches = array_reverse($matches);
$sLink = '';
foreach ($matches as $match) {
// Assuming APP_URL and UNA_URL are defined constants
if (!strstr($match[0], 'https://ci.una.io/') && !strstr($match[0], 'https://ci.una.io/')) {
$sLink = $match[0]; // Returns the first URL that doesn't include the restricted domains
}
}

$text = '';
if ($sLink){
bx_import('BxDolEmbed');
$oEmbed = BxDolEmbed::getObjectInstance('sys_system');
$text = $oEmbed->getHtml($sLink, '');
}

return $text;
}

/**
* Wrap in A tag links in HTML string, which aren't wrapped in A tag yet
* @param $sHtmlOrig - HTML string
Expand Down
13 changes: 12 additions & 1 deletion install/sql/system.sql
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ CREATE TABLE `sys_objects_embeds` (


INSERT INTO `sys_objects_embeds` (`object`, `title`, `override_class_name`, `override_class_file`) VALUES
('sys_system', 'System', 'BxTemplEmbedSystem', ''),
('sys_embedly', 'Embedly', 'BxTemplEmbedEmbedly', ''),
('sys_iframely', 'Iframely', 'BxTemplEmbedIframely', ''),
('sys_oembed', 'Oembed', 'BxTemplEmbedOembed', '');
Expand All @@ -89,6 +90,16 @@ CREATE TABLE `sys_iframely_data` (
PRIMARY KEY (id)
);



CREATE TABLE `sys_embeded_data` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`url` varchar(255) DEFAULT NULL,
`data` text DEFAULT NULL,
`added` int(11) DEFAULT NULL,
`theme` varchar(10) DEFAULT NULL,
PRIMARY KEY (id)
);
-- --------------------------------------------------------


Expand Down Expand Up @@ -505,7 +516,7 @@ INSERT INTO `sys_options`(`category_id`, `name`, `caption`, `value`, `type`, `ex

(@iCategoryId, 'useLikeOperator', '_adm_stg_cpt_option_use_like_operator', 'on', 'checkbox', '', '', '', 45),

(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', 'sys_oembed', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79),
(@iCategoryId, 'sys_embed_default', '_adm_stg_cpt_option_sys_embed_default', 'sys_system', 'select', 'a:3:{s:6:"module";s:6:"system";s:6:"method";s:25:"get_options_embed_default";s:5:"class";s:13:"TemplServices";}', '', '', 79),
(@iCategoryId, 'sys_embedly_api_key', '_adm_stg_cpt_option_sys_embedly_api_key', '', 'digit', '', '', '', 80),

(@iCategoryId, 'sys_iframely_api_key', '_adm_stg_cpt_option_sys_iframely_api_key', '', 'digit', '', '', '', 90);
Expand Down
18 changes: 2 additions & 16 deletions modules/boonex/timeline/classes/BxTimelineModule.php
Original file line number Diff line number Diff line change
Expand Up @@ -2241,23 +2241,9 @@ public function serviceGetBlockItem()
));

$aItemData = $this->getItemData($iItemId, $aParams);

if (bx_is_api()){
$aEventAdd = [
'author_data' => BxDolProfile::getData($aItemData['event']['object_owner_id'])
];

$oMenuActions = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_actions_all'));
if(!$oMenuActions)
$oMenuActions = BxDolMenu::getObjectInstance($this->_oConfig->getObject('menu_item_actions'));
if($oMenuActions !== false) {
$oMenuActions->setEvent($aItemData['event'], $aParams);

$aEventAdd['menu_actions'] = $oMenuActions->getCodeAPI();
}

$aItemData['event'] = array_merge($aItemData['event'], $aEventAdd);

if (bx_is_api()){
$aItemData['event'] = $this->_oTemplate->_getPostApi($aItemData['event'], $aParams);
return [bx_api_get_block('feed_item', $aItemData)];
}

Expand Down
2 changes: 2 additions & 0 deletions modules/boonex/timeline/classes/BxTimelineTemplate.php
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,7 @@ public function _getPostApi(&$aEvent, $aParams = [], $aEventAdd = [])
];
}

if ($aEvent['content']['url'])
$aEvent['url'] = bx_ltrim_str($aEvent['content']['url'], BX_DOL_URL_ROOT);

if(!empty($aEvent['content']) && !empty($aEvent['content']['text'])) {
Expand All @@ -1958,6 +1959,7 @@ public function _getPostApi(&$aEvent, $aParams = [], $aEventAdd = [])
$sMethodPrepare .= 'BriefCard';

$aEvent['content']['text'] = $this->$sMethodPrepare($aEvent['content']['text'], $aEvent['id']);
$aEvent['content']['embed'] = bx_linkify_embeded($aEvent['content']['text']);
}

if(empty($aEventAdd['menu_actions'])) {
Expand Down
45 changes: 17 additions & 28 deletions oembed.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,27 @@
require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");

$aLinks = bx_get('l');

bx_import('BxDolEmbed');
$oEmbed = BxDolEmbed::getObjectInstance('sys_iframely');
$oEmbed = BxDolEmbed::getObjectInstance('sys_system');
/*
echo bx_file_get_contents('https://publish.twitter.com/oembed?url=https://twitter.com/callmehouck/status/1780211820424569127', [], 'get', ['Accept: text/html'], $iHttpCode, [], 0, [CURLOPT_USERAGENT => false]);*/


//, bx_get('theme')
if (bx_get('html')){
echo '<style>body, html {margin:0px}</style><div style="max-width:900; margin:0px auto; justify-content: center;" id="ifr">' . $oEmbed->getDataHtml($aLinks, bx_get('theme')) . '<script language="javascript" src="'.BX_DOL_URL_ROOT.'/plugins_public/jquery/jquery.min.js"></script><script>
$(document).ready(function () {
a = ["' . bx_get('hash') . '", $("#ifr").height(),$("#ifr").width()];
try{
window.parent.postMessage(JSON.stringify(a), "*");
window.ReactNativeWebView.postMessage(JSON.stringify(a));
}
catch (e) {}
})
window.addEventListener("message", function(event) {
if (event.data && event.data!=""){
try {
a = JSON.parse(event.data);
} catch (e) {}
if (a && a.method=="resize"){
a = ["' . bx_get('hash') . '", a.height,$(".iframely-embed").width()];
try{
window.parent.postMessage(JSON.stringify(a), "*");
window.ReactNativeWebView.postMessage(JSON.stringify(a));
}
catch (e) {}
}
}
}, false);
/* $a = bx_get_site_info($aLinks, array(
'thumbnailUrl' => array('tag' => 'link', 'content_attr' => 'href'),
'OGImage' => array('name_attr' => 'property', 'name' => 'og:image'),
'icon' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'shortcut icon', 'content_attr' => 'href'),
'icon2' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'icon', 'content_attr' => 'href'),
'icon3' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'apple-touch-icon', 'content_attr' => 'href'),
));
</script></div>';
print_r( $a);*/
echo '<meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;"" /><style>body, html {margin:0px} A{text-decoration:none; color:#222}</style><div style=" margin:0px auto; justify-content: center;" id="ifr">
'.$oEmbed->getHtml($aLinks, '');
exit();
}
echoJson($oEmbed->parseLinks($aLinks));
152 changes: 152 additions & 0 deletions template/scripts/BxBaseEmbedSystem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php defined('BX_DOL') or die('hack attempt');
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup UnaBaseView UNA Base Representation Classes
* @{
*/

/**
* Iframely integration.
* @see BxDolEmbed
*/
class BxBaseEmbedSystem extends BxDolEmbed
{
public function __construct ($aObject, $oTemplate)
{
$this->_sTableName = 'sys_embeded_data';
parent::__construct ($aObject);

if ($oTemplate)
$this->_oTemplate = $oTemplate;
else
$this->_oTemplate = BxDolTemplate::getInstance();
}

public function getLinkHTML ($sLink, $sTitle = '', $sMaxWidth = '')
{
$aAttrs = array(
'title' => bx_html_attribute($sTitle),
);

// check for external link
if (strncmp(BX_DOL_URL_ROOT, $sLink, strlen(BX_DOL_URL_ROOT)) !== 0) {
$aAttrs['target'] = '_blank';

if (getParam('sys_add_nofollow') == 'on')
$aAttrs['rel'] = 'nofollow';
}

return $this->_oTemplate->parseHtmlByName('embed_iframely_link.html', array(
'link' => $sLink,
'title' => $sTitle,
'attrs' => bx_convert_array2attrs($aAttrs),
'width' => $sMaxWidth,
));
}

public function addProcessLinkMethod ()
{
return "
<script>
function bx_embed_link(e)
{
window.iframely && iframely.load(e);
}
</script>";
}



public function getDataFromApi ($sUrl, $sTheme)
{
$a = bx_get_site_info($sUrl, array(
'thumbnailUrl' => array('tag' => 'link', 'content_attr' => 'href'),
'OGImage' => array('name_attr' => 'property', 'name' => 'og:image'),
'icon' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'shortcut icon', 'content_attr' => 'href'),
'icon2' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'icon', 'content_attr' => 'href'),
'icon3' => array('tag' => 'link', 'name_attr' => 'rel', 'name' => 'apple-touch-icon', 'content_attr' => 'href'),
));

$a['image'] = $a['OGImage'] ? $a['OGImage'] : $a['thumbnailUrl'];
$a['logo'] = $a['icon2'] ? $a['icon2'] : ($a['icon3'] ? $a['icon3'] : $a['icon']);
$a['url'] = $sUrl;


unset($a['OGImage']);
unset($a['thumbnailUrl']);
unset($a['icon2']);
unset($a['icon3']);
unset($a['icon']);

if ($a['image']){
$oStorage = BxDolStorage::getObjectInstance('sys_images');

$iMediaId = $oStorage->storeFileFromUrl($a['image'], false);
if ($iMediaId){
$a['image'] = $oStorage->getFileUrlById($iMediaId);
}
}

if ($a['image'] == ''){
$b = json_decode(bx_file_get_contents("https://api.microlink.io/?url=" . $sUrl), true);
$a = [
'title' => $b['data']['title'],
'description' => $b['data']['description'],
'image' => $b['data']['image']['url'],
'logo' => $b['data']['logo']['url'],
'url' => $sUrl,
];
}

$aU = parse_url($sUrl);
$a['domain'] = $aU['host'];
return json_encode($a);
}

public function getDataHtml ($sUrl, $sTheme)
{
$aData = $this->getData($sUrl, $sTheme);
return $aData;
}

public function getHtml ($sUrl, $sTheme)
{
$aData = $this->getData($sUrl, $sTheme);

return '<a href="'.$aData['url'].'" target="_blank" style="text-decoration: none; color: inherit;">
<div style="display: flex; flex-direction: row; column-gap: height: 128px; border: 1px solid #ccc; align-items: stretch;">
<div style="flex: 0 0 128px; height: 128px; background: url('. ($aData['image'] ? $aData['image'] : $aData['logo']) .') center center / cover no-repeat;">
</div>
<div style="flex-grow: 1; display: flex; flex-direction: column; justify-content: space-between; overflow: hidden;margin: 0 1rem">
<div style="padding-top: 0.5rem; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; text-overflow: ellipsis"><b> '.$aData['title'].'</b></div>
<div style="display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; text-overflow: ellipsis;">
'.$aData['description'].'
</div>
<div style="display: flex; flex-direction: row; column-gap: 8px; align-items: center; padding-bottom: 0.5rem;">
<img src="'.$aData['logo'].'" width=24 height=24 >'.$aData['domain'].'
</div>
</div>
</div>
</a>';

}

public function parseLinks(&$aLinks) {
$aResult = [];
if ($aLinks && is_array($aLinks)) {
$oEmbera = $this->getEmberaInstance();

foreach ($aLinks as $sLink) {
$sHtml = $oEmbera->autoEmbed($sLink);
//if nothing to change/embed then return empty string to not replace anything on a frontend
$aResult[] = ['html' => $sHtml != $sLink ? $sHtml : ''];
}
}
return $aResult;
}

}

/** @} */
Loading

0 comments on commit 682b583

Please sign in to comment.