From cf3752e80273d93964305e43481fabc370888a47 Mon Sep 17 00:00:00 2001 From: brettp Date: Thu, 8 Jul 2010 18:51:34 +0000 Subject: Pulled ECML regex into a constant. Added ecml_get_keywords(), ecml_parse_string(), ecml_extract_keywords(), ecml_get_keyword_info(). Added callback for resolving ECML given an embed code / URL. Removed unused page setup hook. Added web services support. Updated docs. git-svn-id: http://code.elgg.org/elgg/trunk@6664 36083f99-b078-4883-b0ff-0f9b5a30f544 --- mod/ecml/README.txt | 30 ++++++++- mod/ecml/ecml_functions.php | 69 ++++++++++++++++++++ mod/ecml/start.php | 151 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 217 insertions(+), 33 deletions(-) (limited to 'mod/ecml') diff --git a/mod/ecml/README.txt b/mod/ecml/README.txt index 7d59d6dbc..3c18998cc 100644 --- a/mod/ecml/README.txt +++ b/mod/ecml/README.txt @@ -7,7 +7,8 @@ CONTENTS: 3.1 Utility keywords 'entity' and 'view' 3.2 Embedded 3rd party media 4. Custom ECML Keywords - 5. Hints and Quirks + 5. Embed support + 6. Hints and Quirks 1. OVERVIEW @@ -116,6 +117,7 @@ CONTENTS: function buttonizer_ecml_keywords($hook, $type, $value, $params) { $value['buttonizer'] = array( + 'name' => 'Buttonizer', 'view' => 'buttonizer/ecml/buttonizer', 'description' => 'Makes your text a button! What could be better?', 'usage' => 'Use [buttonizer text="My text"] to make "My text" a button!' @@ -143,7 +145,31 @@ CONTENTS: but is much simpler for the user. -5. HINTS AND QUIRKS +5. EMBED SUPPORT + + ECML and the Embed plugin are closely related in that Embed serves + as a sort of front end for ECML. Especially with 3rd party web + services, where URLs and embed codes vary greatly, having a system + in place that allows a user to easily generate and insert ECML + is benificial. + + Currently, only web services ECML keywords are supported in the + embed plugin. Registering a web service keyword looks like this: + + $value[youtube] = array( + 'name' => 'Youtube', + 'view' => "ecml/keywords/youtube", + 'description' => 'Embed YouTube videos', + 'usage' => 'Use src="URL".', + + // important bits + 'type' => 'web_service', + 'params' => array('src', 'width', 'height') // a list of supported params + 'embed' => 'src="%s"' // a sprintf string of the require param format. Added automatically to [keyword $here] + ); + + +6. HINTS AND QUIRKS * A custom keyword is slightly more complicated to implement, but is much simpler for the end user to use. diff --git a/mod/ecml/ecml_functions.php b/mod/ecml/ecml_functions.php index eba8460b2..a4ec8be4f 100644 --- a/mod/ecml/ecml_functions.php +++ b/mod/ecml/ecml_functions.php @@ -9,6 +9,39 @@ * @link http://elgg.org/ */ +/** + * Parses a string for ECML. + * + * @param string $string + * @return string $string with ECML replaced by HTML. + */ +function ecml_parse_string($string, $view = NULL) { + global $CONFIG; + + $CONFIG->ecml_current_view = $view; + + return preg_replace_callback(ECML_KEYWORD_REGEX, 'ecml_parse_view_match', $string); +} + +/** + * Returns ECML-style keywords found in $string. + * Doesn't validate them. + * Returns an array of keyword => arguments + * + * @param string $string + * @return array + */ +function ecml_extract_keywords($string) { + $return = array(); + + if (preg_match_all(ECML_KEYWORD_REGEX, $string, $matches)) { + foreach ($matches[1] as $i => $keyword) { + $return[] = array('keyword' => $keyword, 'params' => $matches[2][$i]); + } + } + + return $return; +} /** * Parse ECML keywords @@ -204,6 +237,11 @@ function ecml_is_valid_keyword($keyword, $view = NULL) { if (!isset($CONFIG->ecml_keywords[$keyword])) { return FALSE; } + + // don't check against views. Already know it's a real one. + if (!$view) { + return TRUE; + } // this keyword is restricted to certain views if (isset($CONFIG->ecml_keywords[$keyword]['restricted']) @@ -222,3 +260,34 @@ function ecml_is_valid_keyword($keyword, $view = NULL) { return $r; } + +/** + * Grab the ECML keywords as saved in $CONFIG or regenerate. + */ +function ecml_get_keywords($recache = FALSE) { + global $CONFIG; + + if (isset($CONFIG->ecml_keywords) && !$recache) { + return $CONFIG->ecml_keywords; + } + + $keywords = trigger_plugin_hook('get_keywords', 'ecml', NULL, array()); + $CONFIG->ecml_keywords = $keywords; + return $keywords; +} + +/** + * Return basic info about the keyword. + * + * @param string $keyword + * @return array + */ +function ecml_get_keyword_info($keyword) { + global $CONFIG; + + if (isset($CONFIG->ecml_keywords[$keyword])) { + return $CONFIG->ecml_keywords[$keyword]; + } + + return FALSE; +} \ No newline at end of file diff --git a/mod/ecml/start.php b/mod/ecml/start.php index 598af0185..1c1bbd3fd 100644 --- a/mod/ecml/start.php +++ b/mod/ecml/start.php @@ -24,13 +24,18 @@ function ecml_init() { define('ECML_ATTR_SEPARATOR', ' '); define('ECML_ATTR_OPERATOR', '='); + + // find alphanumerics (keywords) possibly followed by everything that is not a ] (args) and all surrounded by [ ]s + define('ECML_KEYWORD_REGEX', '/\[([a-z0-9\.]+)([^\]]+)?\]/'); // help page register_page_handler('ecml', 'ecml_help_page_handler'); // admin access page register_page_handler('ecml_admin', 'ecml_admin_page_handler'); - register_elgg_event_handler('pagesetup', 'system', 'ecml_pagesetup'); + + // ecml validator for embed + register_page_handler('ecml_generate', 'ecml_generate_page_handler'); // CSS for admin access elgg_extend_view('css', 'ecml/admin/css'); @@ -70,16 +75,9 @@ function ecml_init() { // but probably makes more sense from a UI perspective as a whitelist. // uses [views][view_name] = array(keywords, not, allowed) $CONFIG->ecml_permissions = unserialize(get_plugin_setting('ecml_permissions', 'ecml')); -} - -/** - * Page setup. Adds admin controls to the admin panel for granular permission - */ -function ecml_pagesetup(){ - if (get_context() == 'admin' && isadminloggedin()) { - global $CONFIG; - - } + + // 3rd party media embed section + register_plugin_hook('embed_get_sections', 'all', 'ecml_embed_web_services_hook'); } /** @@ -93,6 +91,74 @@ function ecml_help_page_handler($page) { echo page_draw(elgg_echo('ecml:help'), $body); } +/** + * Generate ECML given a URL or embed link and service. + * Doesn't check if the resource actually exists. + * Outputs JSON. + * + * @param unknown_type $page + */ +function ecml_generate_page_handler($page) { + $service = trim(get_input('service')); + $resource = trim(get_input('resource')); + + // if standard ECML is passed, guess the service from that instead + // only support one. + if (elgg_substr($resource, 0, 1) == '[') { + if ($keywords = ecml_extract_keywords($resource)) { + $keyword = $keywords[0]['keyword']; + $ecml_info = ecml_get_keyword_info($keyword); + $html = ecml_parse_string($resource); + + echo json_encode(array( + 'status' => 'success', + 'ecml' => $resource, + 'html' => $html + )); + + exit; + } + } + + if (!$service || !$resource) { + echo json_encode(array( + 'status' => 'error', + 'message' => elgg_echo('ecml:embed:invalid_web_service_keyword') + )); + + exit; + } + + $ecml_info = ecml_get_keyword_info($service); + + if ($ecml_info) { + // don't allow embedding for restricted. + if (isset($ecml_info['restricted'])) { + $result = array( + 'status' => 'error', + 'message' => elgg_echo('ecml:embed:cannot_embed'), + ); + } else { + // @todo pull this out into a function. allow optional arguments. + $ecml = "[$service " . sprintf($ecml_info['embed_format'], $resource) . ']'; + $html = ecml_parse_string($ecml, NULL); + $result = array( + 'status' => 'success', + 'ecml' => $ecml, + 'html' => $html + ); + } + } else { + $result = array( + 'status' => 'error', + 'message' => elgg_echo('ecml:embed:invalid_web_service_keyword') + ); + } + + echo json_encode($result); + exit; +} + /** * Display a admin area for ECML * @@ -118,13 +184,7 @@ function ecml_admin_page_handler($page) { function ecml_parse_view($hook, $entity_type, $return_value, $params) { global $CONFIG; - // give me everything that is not a ], possibly followed by a :, and surrounded by [ ]s - //$keyword_regex = '/\[\[([a-z0-9_]+):?([^\]]+)?\]\]/'; - $keyword_regex = '/\[([a-z0-9\.]+)([^\]]+)?\]/'; - $CONFIG->ecml_current_view = $params['view']; - $return_value = preg_replace_callback($keyword_regex, 'ecml_parse_view_match', $return_value); - - return $return_value; + return ecml_parse_string($return_value, $params['view']); } @@ -141,26 +201,37 @@ function ecml_keyword_hook($hook, $type, $value, $params) { // I keep going back and forth about entity and view. They're powerful, but // a great way to let a site get hacked if the admin doesn't lock them down. $keywords = array( - 'youtube', - 'slideshare', - 'vimeo', - 'googlemaps', - 'scribd', - 'blip.tv', - 'dailymotion', - 'livevideo', - 'redlasso', - 'entity' + 'youtube' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'), + 'slideshare' => array('params' => array('id', 'width', 'height'), 'embed_format' => 'id="%s"'), + 'vimeo' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'), + 'googlemaps' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'), + //'scribd' + 'blip.tv' => array('params' => array('width', 'height'), 'embed_format' => '%s'), + 'dailymotion' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'), + 'livevideo' => array('params' => array('src', 'width', 'height'), 'embed_format' => 'src="%s"'), + 'redlasso' => array('params' => array('id', 'width', 'height'), 'embed_format' => 'id="%s"'), ); - foreach ($keywords as $keyword) { + foreach ($keywords as $keyword => $info) { $value[$keyword] = array( + 'name' => elgg_echo("ecml:keywords:$keyword"), 'view' => "ecml/keywords/$keyword", 'description' => elgg_echo("ecml:keywords:$keyword:desc"), - 'usage' => elgg_echo("ecml:keywords:$keyword:usage") + 'usage' => elgg_echo("ecml:keywords:$keyword:usage"), + 'type' => 'web_service', + 'params' => $info['params'], + 'embed_format' => $info['embed_format'] ); } - + + // default entity keyword + $value['entity'] = array( + 'name' => elgg_echo('ecml:keywords:entity'), + 'view' => "ecml/keywords/entity", + 'description' => elgg_echo("ecml:keywords:entity:desc"), + 'usage' => elgg_echo("ecml:keywords:entity:usage") + ); + return $value; } @@ -178,5 +249,23 @@ function ecml_views_hook($hook, $type, $value, $params) { return $value; } +/** + * Show the special Web Services embed section. + * + * @param unknown_type $hook + * @param unknown_type $type + * @param unknown_type $value + * @param unknown_type $params + */ +function ecml_embed_web_services_hook($hook, $type, $value, $params) { + // we're using a view override for this section's content + // so only need to pass the name. + $value['web_services'] = array( + 'name' => elgg_echo('embed:web_services') + ); + + return $value; +} + // be sure to run after other plugins register_elgg_event_handler('init', 'system', 'ecml_init', 9999); \ No newline at end of file -- cgit v1.2.3