1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
<?php
/**
* Provides the ECML service to plugins.
*
* @package ECML
*
* @todo
* Granular access to keywords based upon view.
* Update docs / help
* Check for SQL injection problems.
* Check entity keyword views against fullview. Force to FALSE?
*/
/**
* Init ECML
*/
function ecml_init() {
require_once(dirname(__FILE__) . '/ecml_functions.php');
global $CONFIG;
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');
// ecml validator for embed
register_page_handler('ecml_generate', 'ecml_generate_page_handler');
// CSS for admin access
elgg_extend_view('css', 'ecml/admin/css');
// admin action to save permissions
register_action('settings/ecml/save', FALSE, dirname(__FILE__) . '/actions/save_permissions.php', TRUE);
// show ECML-enabled icon on free-text input areas
//elgg_extend_view('input/longtext', 'ecml/input_ext', 0);
//elgg_extend_view('input/plaintext', 'ecml/input_ext');
//elgg_extend_view('input/text', 'ecml/input_ext');
// add parsing for core views.
elgg_register_plugin_hook_handler('get_views', 'ecml', 'ecml_views_hook');
// get register the views we want to parse for ecml
// @todo will need to do profiling to see if it would be faster
// to foreach through this list and register to specific views or
// do the check in a single plugin hook.
// Wants array('view_name' => 'Short Description')
$CONFIG->ecml_parse_views = elgg_trigger_plugin_hook('get_views', 'ecml', NULL, array());
foreach ($CONFIG->ecml_parse_views as $view => $desc) {
elgg_register_plugin_hook_handler('view', $view, 'ecml_parse_view');
}
// provide a few built-in ecml keywords.
// @todo could pull this out into an array here to save an API call.
elgg_register_plugin_hook_handler('get_keywords', 'ecml', 'ecml_keyword_hook');
// grab the list of keywords and their views from plugins
$CONFIG->ecml_keywords = elgg_trigger_plugin_hook('get_keywords', 'ecml', NULL, array());
// grab permissions for specific views/contexts
// this is a black list.
// it's more efficient to use this as a blacklist
// 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'));
// 3rd party media embed section
elgg_register_plugin_hook_handler('embed_get_sections', 'all', 'ecml_embed_web_services_hook');
// remove ecml when stripping tags
elgg_register_plugin_hook_handler('format', 'strip_tags', 'ecml_strip_tags');
}
/**
* Display a help page for valid ECML keywords on this page.
*
* @param array $page
*/
function ecml_help_page_handler($page) {
if (!isset($page[0]) || empty($page[0])) {
$content = elgg_view('ecml/help');
$body = elgg_view_layout('one_column_with_sidebar', $content);
echo elgg_view_page(elgg_echo('ecml:help'), $body);
} else {
// asking for detailed help about a keyword
$keyword = $page[0];
$content = elgg_view('ecml/keyword_help', array('keyword' => $keyword));
if (get_input('ajax', FALSE)) {
echo $content;
exit;
} else {
$body = elgg_view_layout('one_column_with_sidebar', $content);
echo elgg_view_page(elgg_echo('ecml:help'), $body);
}
}
return TRUE;
}
/**
* 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
*
* @param array $page
*/
function ecml_admin_page_handler($page) {
admin_gatekeeper();
elgg_set_context('admin');
$content = elgg_view('ecml/admin/ecml_admin');
$body = elgg_view_layout('one_column_with_sidebar', $content);
echo elgg_view_page(elgg_echo('ecml:admin'), $body);
}
/**
* Parses a registered view / context for supported keywords.
*
* @param unknown_type $hook
* @param unknown_type $entity_type
* @param unknown_type $return_value
* @param unknown_type $params
* @return string
*/
function ecml_parse_view($hook, $entity_type, $return_value, $params) {
global $CONFIG;
return ecml_parse_string($return_value, $params['view']);
}
/**
* Register default keywords.
*
* @param unknown_type $hook
* @param unknown_type $type
* @param unknown_type $value
* @param unknown_type $params
* @return unknown_type
*/
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' => 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 => $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"),
'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;
}
/**
* Register default views to parse
*
* @param unknown_type $hook
* @param unknown_type $type
* @param unknown_type $value
* @param unknown_type $params
*/
function ecml_views_hook($hook, $type, $value, $params) {
$value['annotation/generic_comment'] = elgg_echo('ecml:views:annotation_generic_comment');
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('ecml:embed:web_services')
);
return $value;
}
/**
* Remove ecml code for elgg_strip_tags()
*
* @param unknown_type $hook
* @param unknown_type $type
* @param unknown_type $value
* @param unknown_type $params
*/
function ecml_strip_tags($hook, $type, $value, $params) {
return preg_replace(ECML_KEYWORD_REGEX, '', $value);
}
// be sure to run after other plugins
elgg_register_event_handler('init', 'system', 'ecml_init', 9999);
|