';
+} else {
+ // if this user logged in through twitter and never set up an email address, don't
+ // let them disassociate their account.
+ if ($user->email) {
+ $url = elgg_get_site_url() . "twitter_api/revoke";
+ echo '
';
-} else {
- // if this user logged in through twitter and never set up an email address, don't
- // let them disassociate their account.
- if ($user->email) {
- $url = elgg_get_site_url() . "twitter_api/revoke";
- echo '
+HTML;
diff --git a/mod/embed/views/default/embed/list.php b/mod/embed/views/default/embed/list.php
new file mode 100644
index 000000000..e36280e88
--- /dev/null
+++ b/mod/embed/views/default/embed/list.php
@@ -0,0 +1,61 @@
+ element
+ * @uses $vars['item_class'] Additional CSS class for the
';
-
-if (isset($js)) {
- echo '';
-}
diff --git a/mod/embed/views/default/embed/item.php b/mod/embed/views/default/embed/item.php
index a64a67d8b..c6faa450b 100644
--- a/mod/embed/views/default/embed/item.php
+++ b/mod/embed/views/default/embed/item.php
@@ -2,7 +2,7 @@
/**
* Embeddable content list item view
*
- * @uses $vars['entity']
+ * @uses $vars['entity'] ElggEntity object
*/
$entity = $vars['entity'];
diff --git a/mod/embed/views/default/embed/list.php b/mod/embed/views/default/embed/list.php
index e36280e88..c13639cff 100644
--- a/mod/embed/views/default/embed/list.php
+++ b/mod/embed/views/default/embed/list.php
@@ -9,9 +9,6 @@
* @uses $vars['limit'] Number of items per page
* @uses $vars['count'] Number of items in the complete list
*
- * @uses $vars['pagination'] Show pagination? (default: true)
- * @uses $vars['position'] Position of the pagination: before, after, or both
- * @uses $vars['full_view'] Show the full view of the items (default: false)
* @uses $vars['list_class'] Additional CSS class for the
element
* @uses $vars['item_class'] Additional CSS class for the
elements
*/
diff --git a/mod/embed/views/default/embed/tabs.php b/mod/embed/views/default/embed/tabs.php
deleted file mode 100644
index 3f377fee5..000000000
--- a/mod/embed/views/default/embed/tabs.php
+++ /dev/null
@@ -1,40 +0,0 @@
- $section_info) {
- $tab = array(
- 'title' => $section_info['name'],
- 'url' => '#',
- 'url_class' => 'embed-section',
- 'url_id' => $section_id,
- );
-
- if ($section_id == $active_section) {
- $tab['selected'] = TRUE;
- }
- $tabs[] = $tab;
-}
-
-// make sure upload is always the last tab
-if ($upload_sections) {
- $tabs[] = array(
- 'title' => elgg_echo('embed:upload'),
- 'url' => '#',
- 'url_class' => 'embed-section',
- 'url_id' => 'upload',
- 'selected' => ($active_section == 'upload')
- );
-}
-
-echo elgg_view('navigation/tabs', array('tabs' => $tabs));
diff --git a/mod/embed/views/default/group/default/embed.php b/mod/embed/views/default/group/default/embed.php
deleted file mode 100644
index bf51f0a7d..000000000
--- a/mod/embed/views/default/group/default/embed.php
+++ /dev/null
@@ -1,5 +0,0 @@
-getURL() .'">' . $vars['entity']->name . '';
- }
-?>
\ No newline at end of file
diff --git a/mod/embed/views/default/js/embed/embed.php b/mod/embed/views/default/js/embed/embed.php
index 49c277b69..e60c6b367 100644
--- a/mod/embed/views/default/js/embed/embed.php
+++ b/mod/embed/views/default/js/embed/embed.php
@@ -1,4 +1,3 @@
-//";
diff --git a/mod/embed/views/default/js/embed/embed.php b/mod/embed/views/default/js/embed/embed.php
index e60c6b367..37246ee8a 100644
--- a/mod/embed/views/default/js/embed/embed.php
+++ b/mod/embed/views/default/js/embed/embed.php
@@ -3,7 +3,7 @@ elgg.provide('elgg.embed');
elgg.embed.init = function() {
// inserts the embed content into the textarea
- $(".embed_data").live('click', elgg.embed.insert);
+ $(".embed-item").live('click', elgg.embed.insert);
// caches the current textarea id
$(".embed-control").live('click', function() {
@@ -24,7 +24,7 @@ elgg.embed.init = function() {
/**
* Inserts data attached to an embed list item in textarea
*
- * @todo generalize lightbox closing and wysiwyg refreshing
+ * @todo generalize lightbox closing
*
* @param {Object} event
* @return void
@@ -32,10 +32,23 @@ elgg.embed.init = function() {
elgg.embed.insert = function(event) {
var textAreaId = elgg.embed.textAreaId;
- var content = $(this).data('embed_code');
- $('#' + textAreaId).val($('#' + textAreaId).val() + ' ' + content + ' ');
-
-
+ // generalize this based on a css class attached to what should be inserted
+ var content = ' ' + $(this).find(".elgg-image").html() + ' ';
+
+
+ $('#' + textAreaId).val($('#' + textAreaId).val() + content);
+ $('#' + textAreaId).focus();
+
$.fancybox.close();
@@ -68,7 +81,7 @@ elgg.embed.submit = function(event) {
if (response.status >= 0) {
// @todo - really this should forward to what the registered defined
// For example, forward to images tab if an image was uploaded
- var url = elgg.config.wwwroot + 'embed/embed?active_section=file';
+ var url = elgg.config.wwwroot + 'embed/embed';
$('.embed-wrapper').parent().load(url);
}
}
--
cgit v1.2.3
From bc292c96ac6b118bd7a99509fce1c11bb232aeb2 Mon Sep 17 00:00:00 2001
From: cash
Date: Sat, 1 Oct 2011 16:54:24 -0400
Subject: fixed the forwarding of an embed upload form
---
mod/embed/views/default/js/embed/embed.php | 5 +-
mod/file/views/default/embed/file/content.php | 61 ----------------------
.../views/default/embed/file_upload/content.php | 9 +++-
3 files changed, 9 insertions(+), 66 deletions(-)
delete mode 100644 mod/file/views/default/embed/file/content.php
diff --git a/mod/embed/views/default/js/embed/embed.php b/mod/embed/views/default/js/embed/embed.php
index 37246ee8a..6d4e2e4ea 100644
--- a/mod/embed/views/default/js/embed/embed.php
+++ b/mod/embed/views/default/js/embed/embed.php
@@ -79,9 +79,8 @@ elgg.embed.submit = function(event) {
elgg.system_message(response.system_messages.success);
}
if (response.status >= 0) {
- // @todo - really this should forward to what the registered defined
- // For example, forward to images tab if an image was uploaded
- var url = elgg.config.wwwroot + 'embed/embed';
+ var forward = $('input[name=embed_forward]').val();
+ var url = elgg.normalize_url('embed/tab/' + forward);
$('.embed-wrapper').parent().load(url);
}
}
diff --git a/mod/file/views/default/embed/file/content.php b/mod/file/views/default/embed/file/content.php
deleted file mode 100644
index eadcd1a6d..000000000
--- a/mod/file/views/default/embed/file/content.php
+++ /dev/null
@@ -1,61 +0,0 @@
- elgg_get_logged_in_user_guid(),
- 'type_subtype_pair' => array('object' => 'file'),
- 'count' => true
-);
-
-$count = elgg_get_entities($options);
-
-if ($count) {
- echo "
';
-}
\ No newline at end of file
diff --git a/mod/file/views/default/embed/file_upload/content.php b/mod/file/views/default/embed/file_upload/content.php
index 13c18f745..a530b3194 100644
--- a/mod/file/views/default/embed/file_upload/content.php
+++ b/mod/file/views/default/embed/file_upload/content.php
@@ -9,7 +9,12 @@ $form_vars = array(
);
$upload_content = elgg_view_form('file/upload', $form_vars);
-echo "
" . elgg_echo('embed:upload_type') . "$input
";
echo "
";
echo $upload_content;
-echo "
";
\ No newline at end of file
+echo "
";
+
+// the tab we want to be forwarded to after upload is complete
+echo elgg_view('input/hidden', array(
+ 'name' => 'embed_forward',
+ 'value' => 'file',
+));
\ No newline at end of file
--
cgit v1.2.3
From d7549a210074a29f004642d713ede6ce04703bcc Mon Sep 17 00:00:00 2001
From: cash
Date: Sat, 1 Oct 2011 17:38:47 -0400
Subject: Updated the instructions
---
mod/embed/README.txt | 236 +++++++----------------------
mod/embed/views/default/js/embed/embed.php | 25 ++-
2 files changed, 66 insertions(+), 195 deletions(-)
diff --git a/mod/embed/README.txt b/mod/embed/README.txt
index 33c9fff65..c7ce2e528 100644
--- a/mod/embed/README.txt
+++ b/mod/embed/README.txt
@@ -1,198 +1,74 @@
-Embed plugin - Point-and-click embedding using ECML.
+Embed plugin
CONTENTS:
1. Overview
- 2. Extending Embed
- 1. Registering and Populating Embed Sections
- 2. Registering Upload Sections
- 3. Advanced Layouts
- 4. Javascript
- 3. Other Editors and Embed
+ 2. Adding a Tab
+ 3. Populating a Select Tab
+ 4. Populating an Upload Tab
+ 5. Other WYSIWYG Editors and Embed
1. Overview
The Embed plugin is a simple way to allow users to link to or embed
their personal network content or third party resources in any text area.
-
- Embed includes support for the default input/longtext view, but is easily
- extendable to include support for rich text editors like TinyMCE or CK
- Editor.
+ The Embed plugin adds a menu item to the longtext menu. Clicking on this
+ link pops up a lightbox. The lightbox has two types of tabs: one for
+ selecting content to embed and one for uploading new content.
-2. Extending Embed
- The Embed plugin can be extended by other plugins using a combination
- of plugin hooks and specific views.
-
- Plugins can register a new content section or a new upload section.
-
- Plugins can also provide special views for their embed section, if
- they require something the default view doesn't provide.
+2. Adding a Tab
+ The Embed plugin uses the menu system to manage its tabs. Use
+ elgg_register_menu_item() for the embed menu to add a new tab like this:
+ $item = ElggMenuItem::factory(array(
+ 'name' => 'file',
+ 'text' => elgg_echo('file'),
+ 'section' => 'select',
+ 'data' => array(
+ 'options' => array(
+ 'type' => 'object',
+ 'subtype' => 'file',
+ ),
+ ),
+ ));
+ elgg_register_menu_item('embed', $item);
-2.1 Registering and Populating Embed Sections
- Plugins providing embed content should reply to two hooks: embed_get_sections:all
- and embed_get_items:$section_name.
-
- Embed emits the 'embed_get_sections' hook to populate the tabs of the modal display.
- Plugins supporting embed should reply by pushing an array element to the passed
- $value.
-
- Register plugins hooks like this:
-
- register_plugin_hook('embed_get_sections', 'all', 'my_plugin_embed_get_sections');
-
- function my_plugin_embed_get_sections($hook, $type, $value, $params) {
- $value['videolist'] = array(
- 'name' => elgg_echo('my_plugin'),
- 'layout' => 'list',
- 'icon_size' => 'medium',
- );
-
- return $value;
- }
-
- The index of the returned array is the id used for the Embed section.
-
- Options available in the array value are:
- name => The friendly name to display in the tab
- layout => The layout style to use. Layouts are found in the
- embed/layouts/$layout and embed/item/$layout views.
- Default supported layouts are list and gallery.
- icon_size => The icon size to use for in the item list.
-
-
- Embed emits the 'embed_get_items' hook to populate the embed section. Plugins
- supporting embed should reply by returning an array of ElggEntities, which will
- be formatted by Embed. If you need specific formatting for items, see section 2.3.
-
- register_plugin_hook('embed_get_items', 'videolist', 'videolist_embed_get_items');
-
- function my_plugin_embed_get_items($hook, $type, $value, $params) {
- $options = array(
- 'owner_guid' => get_loggedin_userid(),
- 'type_subtype_pair' => array('object' => 'my_plugin_type'),
- 'count' => TRUE
- );
-
- if ($count = elgg_get_entities($options)) {
- $value['count'] += $count;
-
- unset($options['count']);
- $options['offset'] = $params['offset'];
- $options['limit'] = $params['limit'];
-
- $items = elgg_get_entities($options);
-
- $value['items'] = array_merge($items, $value['items']);
- }
-
- return $value;
- }
-
- Values passed in $params are:
- offset - Offset for entity list.
- limit - Limit for entity list.
- section - The current active section.
- upload_sections - Valid upload sections.
- internal_name - Internal name of the input field
-
- The function should return $value as:
- items - An array of ElggEntities
- count - The count of all available entities to embed
-
- In case other plugins want to mangle the value, be sure to
- check for existing values before appending.
+ Parameters:
+ name: The unique name of the tab.
+ text: The text shown on the tab
+ section: 'select' for embed selection or 'upload' for uploading new content
+ data: an array of parameters for creating the tab and its content. See
+ the two sections below for data key values for the two tab types.
+ Select tab data parameters:
+ options: array of options passed to elgg_list_entities()
-2.2 Registering Upload Sections
- Embed includes a special tab, Upload, that allows users to immediatley
- upload a new item. Like the embed sections, plugins can extend this
- to add their own upload form.
-
- Embed emits the embed_get_upload_sections:all hook to populate the
- dropdown in the upload tab. Plugins should respond to this hook
- by returning an array with details about the upload section:
-
- register_plugin_hook('embed_get_upload_sections', 'all', 'my_plugin_embed_get_upload_sections');
-
- function my_plugin_embed_get_upload_sections($hook, $type, $value, $params) {
- $value['my_plugin'] = array(
- 'name' => elgg_echo('my_plugin'),
- 'view' => 'my_plugin/forms/embed_upload'
- );
-
- return $value;
- }
-
- The array index is the ID of the upload section, and the values are:
- name - The friendly name of the upload section
- view - The view to use for the upload section's content
-
- The upload form view should use AJAX to upload a file and return
- the user to the correct section or automatically insert the new upload
- into the text area. See Tidypics as an example.
-
-
-2.3 Advanced Layouts
- By default, Embed will automatically format items returned by
- embed_get_items hooks. If you need special formatting you can
- override both the content and layout views.
-
- Embed looks for a section-specific views before defaulting to built
- in formatting:
- embed/$section/content - The content of the embed section
- including all headers and navigation elements.
- embed/$section/item/$layout - The content of the embed section
- for the specific layout. Inserted
- between navigation elements.
-
- Embed also supports adhoc layouts that can be shared among different plugins.
- To use a specific layout, register the embed section with your own layout
- and create the appropriate layout view:
-
- function my_plugin_embed_get_sections($hook, $type, $value, $params) {
- $value['videolist'] = array(
- 'name' => elgg_echo('my_plugin'),
- 'layout' => 'shared_embed_layout',
- 'icon_size' => 'medium',
- );
-
- return $value;
- }
-
- Create the views 'embed/layouts/shared_embed_layout' and
- 'embed/items/shared_embed_layout.' See the default list and
- gallery layouts as examples.
-
-
-2.4 Javascript
- If you use a custom layout you need to provide a way to insert
- the user's selection into the current editor. Usually this will be
- an onClick event via Javascript. Embed provides a helper function for
- this:
-
- elggEmbedInsertContent(content, textAreaId)
-
- Content is the pre-formatted content to insert into the text area,
- and textAreaId is the name of the text area. This name is
- sent via GET as 'internal_name.'
-
+ Upload tab data parameters:
+ view: the view used to render the tab content
+
+ See the file plugin for examples of registering both tab types.
+
+
+3. Populating a Select Tab
+ Nothing should be required other than setting the options parameter array
+ when registering the tab. See the view embed/item to see how an entity is
+ rendered.
+
+4. Populating an Upload Tab
+ The view that is registered must be defined. It must include a form for
+ uploading the content. The form must be wrapped in a div with the class
+ .embed-upload. Somewhere in the view must be a hidden input field with the
+ name embed_hidden with its value be the name of the tab to forward the user
+ to when uploading is complete.
+
+ See the view embed/file_upload/content for an example
-3. Other Editors and Embed
+5. Other WYSIWYG Editors and Embed
Embed ships with support for the default input/longtext textarea.
- Plugins replacing this view are expected to include Javascript to
+ Plugins replacing this view are expected to include JaVascript to
allow embed to work with the new editors.
- The elggEmbedInsertContent() JS function can be extened for custom
- text editors by extending the embed/custom_insert_js view. Plugins
- should extend this view with javascript code that inserts
- content into the specific text area. Variables available within
- this view are:
- str content The content to insert.
- str textAreaId The name of the textarea to receive the content.
-
- Note: Extend this view; don't override it. It is important to correctly
- extend this view for compatibility across multiple plugins and textarea
- states. Your custom JS should run without error no matter plugin order
- or rich text editor status. See TinyMCE as an example of how to losely
- extend this function.
\ No newline at end of file
+ To add custom JavaScript into the Embed plugin's elgg.embed.insert() function,
+ override the view embed/custom_insert_js. The textarea jQuery object is
+ available as the variable textArea and the content to be inserted is the
+ variable content. See the TinyMCE plugin for an example of this view.
\ No newline at end of file
diff --git a/mod/embed/views/default/js/embed/embed.php b/mod/embed/views/default/js/embed/embed.php
index 6d4e2e4ea..840d8f89c 100644
--- a/mod/embed/views/default/js/embed/embed.php
+++ b/mod/embed/views/default/js/embed/embed.php
@@ -14,9 +14,9 @@ elgg.embed.init = function() {
});
// special pagination helper for lightbox
- $('.embed-wrapper .elgg-pagination a').live('click', elgg.embed.loadContent);
+ $('.embed-wrapper .elgg-pagination a').live('click', elgg.embed.forward);
- $('.embed-section').live('click', elgg.embed.loadContent);
+ $('.embed-section').live('click', elgg.embed.forward);
$('.embed-upload .elgg-form').live('submit', elgg.embed.submit);
}
@@ -31,25 +31,20 @@ elgg.embed.init = function() {
*/
elgg.embed.insert = function(event) {
var textAreaId = elgg.embed.textAreaId;
+ var textArea = $('#' + textAreaId);
// generalize this based on a css class attached to what should be inserted
var content = ' ' + $(this).find(".elgg-image").html() + ' ';
+ textArea.val(textArea.val() + content);
+ textArea.focus();
+
- $('#' + textAreaId).val($('#' + textAreaId).val() + content);
- $('#' + textAreaId).focus();
-
+
$.fancybox.close();
event.preventDefault();
@@ -98,7 +93,7 @@ elgg.embed.submit = function(event) {
* @param {Object} event
* @return void
*/
-elgg.embed.loadContent = function(event) {
+elgg.embed.forward = function(event) {
$('.embed-wrapper').parent().load($(this).attr('href'));
event.preventDefault();
}
--
cgit v1.2.3
From dc0a24816ee224962511739b312898ffaf19d8ae Mon Sep 17 00:00:00 2001
From: Cash Costello
Date: Sat, 1 Oct 2011 19:36:29 -0400
Subject: more was defined twice in the core language file
---
languages/en.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/languages/en.php b/languages/en.php
index 9d0590b2d..27b07d11c 100644
--- a/languages/en.php
+++ b/languages/en.php
@@ -826,8 +826,6 @@ $english = array(
'top' => 'Top',
'bottom' => 'Bottom',
- 'more' => 'more',
-
'invite' => "Invite",
'resetpassword' => "Reset password",
--
cgit v1.2.3
From 8be10bb100a6a4d9abc6bf7ee928d5c2e60004de Mon Sep 17 00:00:00 2001
From: Cash Costello
Date: Sat, 1 Oct 2011 19:53:37 -0400
Subject: Fixes #3912 checking that the upload succeeded before resizing
---
actions/avatar/upload.php | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/actions/avatar/upload.php b/actions/avatar/upload.php
index 19976ea87..885a16557 100644
--- a/actions/avatar/upload.php
+++ b/actions/avatar/upload.php
@@ -11,6 +11,11 @@ if (!$owner || !($owner instanceof ElggUser) || !$owner->canEdit()) {
forward(REFERER);
}
+if ($_FILES['avatar']['error'] != 0) {
+ register_error(elgg_echo('avatar:upload:fail'));
+ forward(REFERER);
+}
+
//@todo make this configurable?
$icon_sizes = array(
'topbar' => array('w'=>16, 'h'=>16, 'square'=>TRUE, 'upscale'=>TRUE),
@@ -42,7 +47,7 @@ foreach ($icon_sizes as $name => $size_info) {
$file->delete();
}
- system_message(elgg_echo('avatar:resize:fail'));
+ register_error(elgg_echo('avatar:resize:fail'));
forward(REFERER);
}
}
--
cgit v1.2.3
From a186ad16e258c6335e1757a20845c64056b87f15 Mon Sep 17 00:00:00 2001
From: Cash Costello
Date: Sat, 1 Oct 2011 20:09:16 -0400
Subject: Fixes #3913 registering jquery.imgareaselect
---
engine/lib/elgglib.php | 3 +++
views/default/forms/avatar/crop.php | 5 +++--
2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index 7bdc5972a..c62175629 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -2031,7 +2031,10 @@ function elgg_init() {
elgg_register_js('elgg.userpicker', 'js/lib/userpicker.js');
elgg_register_js('elgg.friendspicker', 'js/lib/friends_picker.js');
elgg_register_js('jquery.easing', 'vendors/jquery/jquery.easing.1.3.packed.js');
+ elgg_register_js('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/scripts/jquery.imgareaselect.min.js');
+ elgg_register_css('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/css/imgareaselect-deprecated.css');
+
// Trigger the shutdown:system event upon PHP shutdown.
register_shutdown_function('_elgg_shutdown_hook');
diff --git a/views/default/forms/avatar/crop.php b/views/default/forms/avatar/crop.php
index 9fcae25c4..b97db939c 100644
--- a/views/default/forms/avatar/crop.php
+++ b/views/default/forms/avatar/crop.php
@@ -5,6 +5,9 @@
* @uses $vars['entity']
*/
+elgg_load_js('jquery.imgareaselect');
+elgg_load_css('jquery.imgareaselect');
+
$master_image = $vars['entity']->getIconUrl('master');
?>
@@ -25,8 +28,6 @@ echo elgg_view('input/submit', array('value' => elgg_echo('avatar:create')));
?>
-
-
--
cgit v1.2.3
From 3f3994647b238f05233da5f22f75a88582562308 Mon Sep 17 00:00:00 2001
From: cash
Date: Sat, 1 Oct 2011 21:51:53 -0400
Subject: Fixes #3686 added work around for PHP bug when validating URLs with
dashes
---
mod/bookmarks/actions/bookmarks/save.php | 19 ++++++++++++++++++-
mod/bookmarks/languages/en.php | 3 ++-
2 files changed, 20 insertions(+), 2 deletions(-)
diff --git a/mod/bookmarks/actions/bookmarks/save.php b/mod/bookmarks/actions/bookmarks/save.php
index 19bb3c73a..f240c4b26 100644
--- a/mod/bookmarks/actions/bookmarks/save.php
+++ b/mod/bookmarks/actions/bookmarks/save.php
@@ -24,7 +24,24 @@ if ($address && !preg_match("#^((ht|f)tps?:)?//#i", $address)) {
$address = "http://$address";
}
-if (!$title || !$address || !filter_var($address, FILTER_VALIDATE_URL)) {
+if (!$title || !$address) {
+ register_error(elgg_echo('bookmarks:save:failed'));
+ forward(REFERER);
+}
+
+// see https://bugs.php.net/bug.php?id=51192
+$php_5_2_13_and_below = version_compare(PHP_VERSION, '5.2.14', '<');
+$php_5_3_0_to_5_3_2 = version_compare(PHP_VERSION, '5.3.0', '>=') &&
+ version_compare(PHP_VERSION, '5.3.3', '<');
+
+$validated = false;
+if ($php_5_2_13_and_below || $php_5_3_0_to_5_3_2) {
+ $tmp_address = str_replace("-", "", $address);
+ $validated = filter_var($tmp_address, FILTER_VALIDATE_URL);
+} else {
+ $validated = filter_var($address, FILTER_VALIDATE_URL);
+}
+if (!$validated) {
register_error(elgg_echo('bookmarks:save:failed'));
forward(REFERER);
}
diff --git a/mod/bookmarks/languages/en.php b/mod/bookmarks/languages/en.php
index 1d32a0344..0478e292f 100644
--- a/mod/bookmarks/languages/en.php
+++ b/mod/bookmarks/languages/en.php
@@ -24,7 +24,7 @@ $english = array(
'bookmarks:with' => "Share with",
'bookmarks:new' => "A new bookmark",
'bookmarks:via' => "via bookmarks",
- 'bookmarks:address' => "Address of the resource to bookmark",
+ 'bookmarks:address' => "Address of the bookmark",
'bookmarks:none' => 'No bookmarks',
'bookmarks:delete:confirm' => "Are you sure you want to delete this resource?",
@@ -75,6 +75,7 @@ $english = array(
*/
'bookmarks:save:failed' => "Your bookmark could not be saved. Make sure you've entered a title and address and then try again.",
+ 'bookmarks:save:invalid' => "The address of the bookmark is invalid and could nto be saved.",
'bookmarks:delete:failed' => "Your bookmark could not be deleted. Please try again.",
);
--
cgit v1.2.3
From ad016fd1254aa03afa7c24fdb82b35faa3c5019f Mon Sep 17 00:00:00 2001
From: cash
Date: Sat, 1 Oct 2011 22:08:07 -0400
Subject: Fixes #3860 changed context-sensitive to dynamic to describe menus
---
engine/lib/navigation.php | 8 ++++----
engine/lib/views.php | 13 +++++++------
2 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
index 778da94e9..3f3a8ecd5 100644
--- a/engine/lib/navigation.php
+++ b/engine/lib/navigation.php
@@ -20,20 +20,20 @@
* Menus
* Elgg uses a single interface to manage its menus. Menu items are added with
* {@link elgg_register_menu_item()}. This is generally used for menus that
- * appear only once per page. For context-sensitive menus (such as the hover
+ * appear only once per page. For dynamic menus (such as the hover
* menu for user's avatar), a plugin hook is emitted when the menu is being
* created. The hook is 'register', 'menu:'. For more details on this,
* @see elgg_view_menu().
*
* Menus supported by the Elgg core
* Standard menus:
- * site Site navihgation shown on every page.
+ * site Site navigation shown on every page.
* page Page menu usually shown in a sidebar. Uses Elgg's context.
* topbar Topbar menu shown on every page. The default has two sections.
* footer Like the topbar but in the footer.
* extras Links about content on the page. The RSS link is added to this.
*
- * Context-sensitive (also called just-in-time menus):
+ * Dynamic menus (also called just-in-time menus):
* user_hover Avatar hover menu. The user entity is passed as a parameter.
* entity The set of links shown in the summary of an entity.
* river Links shown on river items.
@@ -51,7 +51,7 @@
*
* @warning Generally you should not use this in response to the plugin hook:
* 'register', 'menu:'. If you do, you may end up with many incorrect
- * links on a context-sensitive menu.
+ * links on a dynamic menu.
*
* @warning A menu item's name must be unique per menu. If more than one menu
* item with the same name are registered, the last menu item takes priority.
diff --git a/engine/lib/views.php b/engine/lib/views.php
index c31f61e84..a18118f32 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -709,9 +709,9 @@ function elgg_view_layout($layout_name, $vars = array()) {
*
* This function triggers a 'register', 'menu:
]*>( | |\s|\u00a0|)<\/p>[\r\n]*| [\r\n]*)$/,"")})}if(a){function r(s,t){i(s.dom.select("a"),function(A){var z=A.parentNode;if(s.dom.isBlock(z)&&z.lastChild===A){s.dom.add(z,"br",{"data-mce-bogus":1})}})}q.onExecCommand.add(function(s,t){if(t==="CreateLink"){r(s)}});q.onSetContent.add(q.selection.onSetContent.add(r))}q.load({initial:true,format:"html"});q.startContent=q.getContent({format:"raw"});q.undoManager.add();q.initialized=true;q.onInit.dispatch(q);q.execCallback("setupcontent_callback",q.id,q.getBody(),q.getDoc());q.execCallback("init_instance_callback",q);q.focus(true);q.nodeChanged({initial:1});i(q.contentCSS,function(s){q.dom.loadCSS(s)});if(v.auto_focus){setTimeout(function(){var s=m.get(v.auto_focus);s.selection.select(s.getBody(),1);s.selection.collapse(1);s.getBody().focus();s.getWin().focus()},100)}x=null},focus:function(u){var y,q=this,s=q.selection,x=q.settings.content_editable,r,p,v=q.getDoc();if(!u){r=s.getRng();if(r.item){p=r.item(0)}q._refreshContentEditable();s.normalize();if(!x){q.getWin().focus()}if(m.isGecko){q.getBody().focus()}if(p&&p.ownerDocument==v){r=v.body.createControlRange();r.addElement(p);r.select()}}if(m.activeEditor!=q){if((y=m.activeEditor)!=null){y.onDeactivate.dispatch(y,q)}q.onActivate.dispatch(q,y)}m._setActive(q)},execCallback:function(u){var p=this,r=p.settings[u],q;if(!r){return}if(p.callbackLookup&&(q=p.callbackLookup[u])){r=q.func;q=q.scope}if(d(r,"string")){q=r.replace(/\.\w+$/,"");q=q?m.resolve(q):0;r=m.resolve(r);p.callbackLookup=p.callbackLookup||{};p.callbackLookup[u]={func:r,scope:q}}return r.apply(q||p,Array.prototype.slice.call(arguments,1))},translate:function(p){var r=this.settings.language||"en",q=m.i18n;if(!p){return""}return q[r+"."+p]||p.replace(/{\#([^}]+)\}/g,function(t,s){return q[r+"."+s]||"{#"+s+"}"})},getLang:function(q,p){return m.i18n[(this.settings.language||"en")+"."+q]||(d(p)?p:"{#"+q+"}")},getParam:function(u,r,p){var s=m.trim,q=d(this.settings[u])?this.settings[u]:r,t;if(p==="hash"){t={};if(d(q,"string")){i(q.indexOf("=")>0?q.split(/[;,](?![^=;,]*(?:[;,]|$))/):q.split(","),function(x){x=x.split("=");if(x.length>1){t[s(x[0])]=s(x[1])}else{t[s(x[0])]=s(x)}})}else{t=q}return t}return q},nodeChanged:function(r){var p=this,q=p.selection,u=q.getStart()||p.getBody();if(p.initialized){r=r||{};u=b&&u.ownerDocument!=p.getDoc()?p.getBody():u;r.parents=[];p.dom.getParent(u,function(s){if(s.nodeName=="BODY"){return true}r.parents.push(s)});p.onNodeChange.dispatch(p,r?r.controlManager||p.controlManager:p.controlManager,u,q.isCollapsed(),r)}},addButton:function(r,q){var p=this;p.buttons=p.buttons||{};p.buttons[r]=q},addCommand:function(p,r,q){this.execCommands[p]={func:r,scope:q||this}},addQueryStateHandler:function(p,r,q){this.queryStateCommands[p]={func:r,scope:q||this}},addQueryValueHandler:function(p,r,q){this.queryValueCommands[p]={func:r,scope:q||this}},addShortcut:function(r,u,p,s){var q=this,v;if(!q.settings.custom_shortcuts){return false}q.shortcuts=q.shortcuts||{};if(d(p,"string")){v=p;p=function(){q.execCommand(v,false,null)}}if(d(p,"object")){v=p;p=function(){q.execCommand(v[0],v[1],v[2])}}i(g(r),function(t){var x={func:p,scope:s||this,desc:u,alt:false,ctrl:false,shift:false};i(g(t,"+"),function(y){switch(y){case"alt":case"ctrl":case"shift":x[y]=true;break;default:x.charCode=y.charCodeAt(0);x.keyCode=y.toUpperCase().charCodeAt(0)}});q.shortcuts[(x.ctrl?"ctrl":"")+","+(x.alt?"alt":"")+","+(x.shift?"shift":"")+","+x.keyCode]=x});return true},execCommand:function(x,v,z,p){var r=this,u=0,y,q;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(x)&&(!p||!p.skip_focus)){r.focus()}y={};r.onBeforeExecCommand.dispatch(r,x,v,z,y);if(y.terminate){return false}if(r.execCallback("execcommand_callback",r.id,r.selection.getNode(),x,v,z)){r.onExecCommand.dispatch(r,x,v,z,p);return true}if(y=r.execCommands[x]){q=y.func.call(y.scope,v,z);if(q!==true){r.onExecCommand.dispatch(r,x,v,z,p);return q}}i(r.plugins,function(s){if(s.execCommand&&s.execCommand(x,v,z)){r.onExecCommand.dispatch(r,x,v,z,p);u=1;return false}});if(u){return true}if(r.theme&&r.theme.execCommand&&r.theme.execCommand(x,v,z)){r.onExecCommand.dispatch(r,x,v,z,p);return true}if(r.editorCommands.execCommand(x,v,z)){r.onExecCommand.dispatch(r,x,v,z,p);return true}r.getDoc().execCommand(x,v,z);r.onExecCommand.dispatch(r,x,v,z,p)},queryCommandState:function(u){var q=this,v,r;if(q._isHidden()){return}if(v=q.queryStateCommands[u]){r=v.func.call(v.scope);if(r!==true){return r}}v=q.editorCommands.queryCommandState(u);if(v!==-1){return v}try{return this.getDoc().queryCommandState(u)}catch(p){}},queryCommandValue:function(v){var q=this,u,r;if(q._isHidden()){return}if(u=q.queryValueCommands[v]){r=u.func.call(u.scope);if(r!==true){return r}}u=q.editorCommands.queryCommandValue(v);if(d(u)){return u}try{return this.getDoc().queryCommandValue(v)}catch(p){}},show:function(){var p=this;n.show(p.getContainer());n.hide(p.id);p.load()},hide:function(){var p=this,q=p.getDoc();if(b&&q){q.execCommand("SelectAll")}p.save();n.hide(p.getContainer());n.setStyle(p.id,"display",p.orgDisplay)},isHidden:function(){return !n.isHidden(this.id)},setProgressState:function(p,q,r){this.onSetProgressState.dispatch(this,p,q,r);return p},load:function(s){var p=this,r=p.getElement(),q;if(r){s=s||{};s.load=true;q=p.setContent(d(r.value)?r.value:r.innerHTML,s);s.element=r;if(!s.no_events){p.onLoadContent.dispatch(p,s)}s.element=r=null;return q}},save:function(u){var p=this,s=p.getElement(),q,r;if(!s||!p.initialized){return}u=u||{};u.save=true;if(!u.no_events){p.undoManager.typing=false;p.undoManager.add()}u.element=s;q=u.content=p.getContent(u);if(!u.no_events){p.onSaveContent.dispatch(p,u)}q=u.content;if(!/TEXTAREA|INPUT/i.test(s.nodeName)){s.innerHTML=q;if(r=n.getParent(p.id,"form")){i(r.elements,function(t){if(t.name==p.id){t.value=q;return false}})}}else{s.value=q}u.element=s=null;return q},setContent:function(u,s){var r=this,q,p=r.getBody(),t;s=s||{};s.format=s.format||"html";s.set=true;s.content=u;if(!s.no_events){r.onBeforeSetContent.dispatch(r,s)}u=s.content;if(!m.isIE&&(u.length===0||/^\s+$/.test(u))){t=r.settings.forced_root_block;if(t){u="<"+t+'> '+t+">"}else{u=' '}p.innerHTML=u;r.selection.select(p,true);r.selection.collapse(true);return}if(s.format!=="raw"){u=new m.html.Serializer({},r.schema).serialize(r.parser.parse(u))}s.content=m.trim(u);r.dom.setHTML(p,s.content);if(!s.no_events){r.onSetContent.dispatch(r,s)}r.selection.normalize();return s.content},getContent:function(q){var p=this,r;q=q||{};q.format=q.format||"html";q.get=true;if(!q.no_events){p.onBeforeGetContent.dispatch(p,q)}if(q.format=="raw"){r=p.getBody().innerHTML}else{r=p.serializer.serialize(p.getBody(),q)}q.content=m.trim(r);if(!q.no_events){p.onGetContent.dispatch(p,q)}return q.content},isDirty:function(){var p=this;return m.trim(p.startContent)!=m.trim(p.getContent({format:"raw",no_events:1}))&&!p.isNotDirty},getContainer:function(){var p=this;if(!p.container){p.container=n.get(p.editorContainer||p.id+"_parent")}return p.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return n.get(this.settings.content_element||this.id)},getWin:function(){var p=this,q;if(!p.contentWindow){q=n.get(p.id+"_ifr");if(q){p.contentWindow=q.contentWindow}}return p.contentWindow},getDoc:function(){var q=this,p;if(!q.contentDocument){p=q.getWin();if(p){q.contentDocument=p.document}}return q.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(p,x,v){var q=this,r=q.settings;if(r.urlconverter_callback){return q.execCallback("urlconverter_callback",p,v,true,x)}if(!r.convert_urls||(v&&v.nodeName=="LINK")||p.indexOf("file:")===0){return p}if(r.relative_urls){return q.documentBaseURI.toRelative(p)}p=q.documentBaseURI.toAbsolute(p,r.remove_script_host);return p},addVisual:function(r){var p=this,q=p.settings;r=r||p.getBody();if(!d(p.hasVisual)){p.hasVisual=q.visual}i(p.dom.select("table,a",r),function(t){var s;switch(t.nodeName){case"TABLE":s=p.dom.getAttrib(t,"border");if(!s||s=="0"){if(p.hasVisual){p.dom.addClass(t,q.visual_table_class)}else{p.dom.removeClass(t,q.visual_table_class)}}return;case"A":s=p.dom.getAttrib(t,"name");if(s){if(p.hasVisual){p.dom.addClass(t,"mceItemAnchor")}else{p.dom.removeClass(t,"mceItemAnchor")}}return}});p.onVisualAid.dispatch(p,r,p.hasVisual)},remove:function(){var p=this,q=p.getContainer();p.removed=1;p.hide();p.execCallback("remove_instance_callback",p);p.onRemove.dispatch(p);p.onExecCommand.listeners=[];m.remove(p);n.remove(q)},destroy:function(q){var p=this;if(p.destroyed){return}if(!q){m.removeUnload(p.destroy);tinyMCE.onBeforeUnload.remove(p._beforeUnload);if(p.theme&&p.theme.destroy){p.theme.destroy()}p.controlManager.destroy();p.selection.destroy();p.dom.destroy();if(!p.settings.content_editable){j.clear(p.getWin());j.clear(p.getDoc())}j.clear(p.getBody());j.clear(p.formElement)}if(p.formElement){p.formElement.submit=p.formElement._mceOldSubmit;p.formElement._mceOldSubmit=null}p.contentAreaContainer=p.formElement=p.container=p.settings.content_element=p.bodyElement=p.contentDocument=p.contentWindow=null;if(p.selection){p.selection=p.selection.win=p.selection.dom=p.selection.dom.doc=null}p.destroyed=1},_addEvents:function(){var B=this,r,C=B.settings,q=B.dom,x={mouseup:"onMouseUp",mousedown:"onMouseDown",click:"onClick",keyup:"onKeyUp",keydown:"onKeyDown",keypress:"onKeyPress",submit:"onSubmit",reset:"onReset",contextmenu:"onContextMenu",dblclick:"onDblClick",paste:"onPaste"};function p(t,D){var s=t.type;if(B.removed){return}if(B.onEvent.dispatch(B,t,D)!==false){B[x[t.fakeType||t.type]].dispatch(B,t,D)}}i(x,function(t,s){switch(s){case"contextmenu":q.bind(B.getDoc(),s,p);break;case"paste":q.bind(B.getBody(),s,function(D){p(D)});break;case"submit":case"reset":q.bind(B.getElement().form||n.getParent(B.id,"form"),s,p);break;default:q.bind(C.content_editable?B.getBody():B.getDoc(),s,p)}});q.bind(C.content_editable?B.getBody():(a?B.getDoc():B.getWin()),"focus",function(s){B.focus(true)});if(m.isGecko){q.bind(B.getDoc(),"DOMNodeInserted",function(t){var s;t=t.target;if(t.nodeType===1&&t.nodeName==="IMG"&&(s=t.getAttribute("data-mce-src"))){t.src=B.documentBaseURI.toAbsolute(s)}})}if(a){function u(){var E=this,G=E.getDoc(),F=E.settings;if(a&&!F.readonly){E._refreshContentEditable();try{G.execCommand("styleWithCSS",0,false)}catch(D){if(!E._isHidden()){try{G.execCommand("useCSS",0,true)}catch(D){}}}if(!F.table_inline_editing){try{G.execCommand("enableInlineTableEditing",false,false)}catch(D){}}if(!F.object_resizing){try{G.execCommand("enableObjectResizing",false,false)}catch(D){}}}}B.onBeforeExecCommand.add(u);B.onMouseDown.add(u)}B.onMouseUp.add(B.nodeChanged);B.onKeyUp.add(function(s,t){var D=t.keyCode;if((D>=33&&D<=36)||(D>=37&&D<=40)||D==13||D==45||D==46||D==8||(m.isMac&&(D==91||D==93))||t.ctrlKey){B.nodeChanged()}});B.onKeyDown.add(function(t,D){if(D.keyCode!=8){return}var F=t.selection.getRng().startContainer;var E=t.selection.getRng().startOffset;while(F&&F.nodeType&&F.nodeType!=1&&F.parentNode){F=F.parentNode}if(F&&F.parentNode&&F.parentNode.tagName==="BLOCKQUOTE"&&F.parentNode.firstChild==F&&E==0){t.formatter.toggle("blockquote",null,F.parentNode);var s=t.selection.getRng();s.setStart(F,0);s.setEnd(F,0);t.selection.setRng(s);t.selection.collapse(false)}});B.onReset.add(function(){B.setContent(B.startContent,{format:"raw"})});if(C.custom_shortcuts){if(C.custom_undo_redo_keyboard_shortcuts){B.addShortcut("ctrl+z",B.getLang("undo_desc"),"Undo");B.addShortcut("ctrl+y",B.getLang("redo_desc"),"Redo")}B.addShortcut("ctrl+b",B.getLang("bold_desc"),"Bold");B.addShortcut("ctrl+i",B.getLang("italic_desc"),"Italic");B.addShortcut("ctrl+u",B.getLang("underline_desc"),"Underline");for(r=1;r<=6;r++){B.addShortcut("ctrl+"+r,"",["FormatBlock",false,"h"+r])}B.addShortcut("ctrl+7","",["FormatBlock",false,"p"]);B.addShortcut("ctrl+8","",["FormatBlock",false,"div"]);B.addShortcut("ctrl+9","",["FormatBlock",false,"address"]);function v(t){var s=null;if(!t.altKey&&!t.ctrlKey&&!t.metaKey){return s}i(B.shortcuts,function(D){if(m.isMac&&D.ctrl!=t.metaKey){return}else{if(!m.isMac&&D.ctrl!=t.ctrlKey){return}}if(D.alt!=t.altKey){return}if(D.shift!=t.shiftKey){return}if(t.keyCode==D.keyCode||(t.charCode&&t.charCode==D.charCode)){s=D;return false}});return s}B.onKeyUp.add(function(s,t){var D=v(t);if(D){return j.cancel(t)}});B.onKeyPress.add(function(s,t){var D=v(t);if(D){return j.cancel(t)}});B.onKeyDown.add(function(s,t){var D=v(t);if(D){D.func.call(D.scope);return j.cancel(t)}})}if(m.isIE){q.bind(B.getDoc(),"controlselect",function(D){var t=B.resizeInfo,s;D=D.target;if(D.nodeName!=="IMG"){return}if(t){q.unbind(t.node,t.ev,t.cb)}if(!q.hasClass(D,"mceItemNoResize")){ev="resizeend";s=q.bind(D,ev,function(F){var E;F=F.target;if(E=q.getStyle(F,"width")){q.setAttrib(F,"width",E.replace(/[^0-9%]+/g,""));q.setStyle(F,"width","")}if(E=q.getStyle(F,"height")){q.setAttrib(F,"height",E.replace(/[^0-9%]+/g,""));q.setStyle(F,"height","")}})}else{ev="resizestart";s=q.bind(D,"resizestart",j.cancel,j)}t=B.resizeInfo={node:D,ev:ev,cb:s}})}if(m.isOpera){B.onClick.add(function(s,t){j.prevent(t)})}if(C.custom_undo_redo){function y(){B.undoManager.typing=false;B.undoManager.add()}q.bind(B.getDoc(),"focusout",function(s){if(!B.removed&&B.undoManager.typing){y()}});B.dom.bind(B.dom.getRoot(),"dragend",function(s){y()});B.onKeyUp.add(function(s,D){var t=D.keyCode;if((t>=33&&t<=36)||(t>=37&&t<=40)||t==13||t==45||D.ctrlKey){y()}});B.onKeyDown.add(function(s,E){var D=E.keyCode,t;if(D==8){t=B.getDoc().selection;if(t&&t.createRange&&t.createRange().item){B.undoManager.beforeChange();s.dom.remove(t.createRange().item(0));y();return j.cancel(E)}}if((D>=33&&D<=36)||(D>=37&&D<=40)||D==13||D==45){if(m.isIE&&D==13){B.undoManager.beforeChange()}if(B.undoManager.typing){y()}return}if((D<16||D>20)&&D!=224&&D!=91&&!B.undoManager.typing){B.undoManager.beforeChange();B.undoManager.typing=true;B.undoManager.add()}});B.onMouseDown.add(function(){if(B.undoManager.typing){y()}})}if(m.isWebKit){q.bind(B.getDoc(),"selectionchange",function(){if(B.selectionTimer){clearTimeout(B.selectionTimer);B.selectionTimer=0}B.selectionTimer=window.setTimeout(function(){B.nodeChanged()},50)})}if(m.isGecko){function A(){var s=B.dom.getAttribs(B.selection.getStart().cloneNode(false));return function(){var t=B.selection.getStart();if(t!==B.getBody()){B.dom.removeAllAttribs(t);i(s,function(D){t.setAttributeNode(D.cloneNode(true))})}}}function z(){var t=B.selection;return !t.isCollapsed()&&t.getStart()!=t.getEnd()}B.onKeyPress.add(function(s,D){var t;if((D.keyCode==8||D.keyCode==46)&&z()){t=A();B.getDoc().execCommand("delete",false,null);t();return j.cancel(D)}});B.dom.bind(B.getDoc(),"cut",function(t){var s;if(z()){s=A();B.onKeyUp.addToTop(j.cancel,j);setTimeout(function(){s();B.onKeyUp.remove(j.cancel,j)},0)}})}},_refreshContentEditable:function(){var q=this,p,r;if(q._isHidden()){p=q.getBody();r=p.parentNode;r.removeChild(p);r.appendChild(p);p.focus()}},_isHidden:function(){var p;if(!a){return 0}p=this.selection.getSel();return(!p||!p.rangeCount||p.rangeCount==0)}})})(tinymce);(function(c){var d=c.each,e,a=true,b=false;c.EditorCommands=function(n){var m=n.dom,p=n.selection,j={state:{},exec:{},value:{}},k=n.settings,q=n.formatter,o;function r(z,y,x){var v;z=z.toLowerCase();if(v=j.exec[z]){v(z,y,x);return a}return b}function l(x){var v;x=x.toLowerCase();if(v=j.state[x]){return v(x)}return -1}function h(x){var v;x=x.toLowerCase();if(v=j.value[x]){return v(x)}return b}function u(v,x){x=x||"exec";d(v,function(z,y){d(y.toLowerCase().split(","),function(A){j[x][A]=z})})}c.extend(this,{execCommand:r,queryCommandState:l,queryCommandValue:h,addCommands:u});function f(y,x,v){if(x===e){x=b}if(v===e){v=null}return n.getDoc().execCommand(y,x,v)}function t(v){return q.match(v)}function s(v,x){q.toggle(v,x?{value:x}:e)}function i(v){o=p.getBookmark(v)}function g(){p.moveToBookmark(o)}u({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(z){var y=n.getDoc(),v;try{f(z)}catch(x){v=a}if(v||!y.queryCommandSupported(z)){if(c.isGecko){n.windowManager.confirm(n.getLang("clipboard_msg"),function(A){if(A){open("http://www.mozilla.org/editor/midasdemo/securityprefs.html","_blank")}})}else{n.windowManager.alert(n.getLang("clipboard_no_support"))}}},unlink:function(v){if(p.isCollapsed()){p.select(p.getNode())}f(v);p.collapse(b)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){var x=v.substring(7);d("left,center,right,full".split(","),function(y){if(x!=y){q.remove("align"+y)}});s("align"+x);r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(y){var v,x;f(y);v=m.getParent(p.getNode(),"ol,ul");if(v){x=v.parentNode;if(/^(H[1-6]|P|ADDRESS|PRE)$/.test(x.nodeName)){i();m.split(x,v);g()}}},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){s(v)},"ForeColor,HiliteColor,FontName":function(y,x,v){s(y,v)},FontSize:function(z,y,x){var v,A;if(x>=1&&x<=7){A=c.explode(k.font_size_style_values);v=c.explode(k.font_size_classes);if(v){x=v[x-1]||x}else{x=A[x-1]||x}}s(z,x)},RemoveFormat:function(v){q.remove(v)},mceBlockQuote:function(v){s("blockquote")},FormatBlock:function(y,x,v){return s(v||"p")},mceCleanup:function(){var v=p.getBookmark();n.setContent(n.getContent({cleanup:a}),{cleanup:a});p.moveToBookmark(v)},mceRemoveNode:function(z,y,x){var v=x||p.getNode();if(v!=n.getBody()){i();n.dom.remove(v,a);g()}},mceSelectNodeDepth:function(z,y,x){var v=0;m.getParent(p.getNode(),function(A){if(A.nodeType==1&&v++==x){p.select(A);return b}},n.getBody())},mceSelectNode:function(y,x,v){p.select(v)},mceInsertContent:function(B,I,K){var y,J,E,z,F,G,D,C,L,x,A,M,v,H;y=n.parser;J=new c.html.Serializer({},n.schema);v='\uFEFF';G={content:K,format:"html"};p.onBeforeSetContent.dispatch(p,G);K=G.content;if(K.indexOf("{$caret}")==-1){K+="{$caret}"}K=K.replace(/\{\$caret\}/,v);if(!p.isCollapsed()){n.getDoc().execCommand("Delete",false,null)}E=p.getNode();G={context:E.nodeName.toLowerCase()};F=y.parse(K,G);A=F.lastChild;if(A.attr("id")=="mce_marker"){D=A;for(A=A.prev;A;A=A.walk(true)){if(A.type==3||!m.isBlock(A.name)){A.parent.insert(D,A,A.name==="br");break}}}if(!G.invalid){K=J.serialize(F);A=E.firstChild;M=E.lastChild;if(!A||(A===M&&A.nodeName==="BR")){m.setHTML(E,K)}else{p.setContent(K)}}else{p.setContent(v);E=n.selection.getNode();z=n.getBody();if(E.nodeType==9){E=A=z}else{A=E}while(A!==z){E=A;A=A.parentNode}K=E==z?z.innerHTML:m.getOuterHTML(E);K=J.serialize(y.parse(K.replace(//i,function(){return J.serialize(F)})));if(E==z){m.setHTML(z,K)}else{m.setOuterHTML(E,K)}}D=m.get("mce_marker");C=m.getRect(D);L=m.getViewPort(n.getWin());if((C.y+C.h>L.y+L.h||C.yL.x+L.w||C.x")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual;n.addVisual()},mceReplaceContent:function(y,x,v){n.execCommand("mceInsertContent",false,v.replace(/\{\$selection\}/g,p.getContent({format:"text"})))},mceInsertLink:function(z,y,x){var v;if(typeof(x)=="string"){x={href:x}}v=m.getParent(p.getNode(),"a");x.href=x.href.replace(" ","%20");if(!v||!x.href){q.remove("link")}if(x.href){q.apply("link",x,v)}},selectAll:function(){var x=m.getRoot(),v=m.createRng();v.setStart(x,0);v.setEnd(x,x.childNodes.length);n.selection.setRng(v)}});u({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){return t("align"+v.substring(7))},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){return t(v)},mceBlockQuote:function(){return t("blockquote")},Outdent:function(){var v;if(k.inline_styles){if((v=m.getParent(p.getStart(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}if((v=m.getParent(p.getEnd(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}}return l("InsertUnorderedList")||l("InsertOrderedList")||(!k.inline_styles&&!!m.getParent(p.getNode(),"BLOCKQUOTE"))},"InsertUnorderedList,InsertOrderedList":function(v){return m.getParent(p.getNode(),v=="insertunorderedlist"?"UL":"OL")}},"state");u({"FontSize,FontName":function(y){var x=0,v;if(v=m.getParent(p.getNode(),"span")){if(y=="fontsize"){x=v.style.fontSize}else{x=v.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()}}return x}},"value");if(k.custom_undo_redo){u({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}}})(tinymce);(function(b){var a=b.util.Dispatcher;b.UndoManager=function(f){var d,e=0,h=[],c;function g(){return b.trim(f.getContent({format:"raw",no_events:1}))}return d={typing:false,onAdd:new a(d),onUndo:new a(d),onRedo:new a(d),beforeChange:function(){c=f.selection.getBookmark(2,true)},add:function(m){var j,k=f.settings,l;m=m||{};m.content=g();l=h[e];if(l&&l.content==m.content){return null}if(h[e]){h[e].beforeBookmark=c}if(k.custom_undo_redo_levels){if(h.length>k.custom_undo_redo_levels){for(j=0;j0){k=h[--e];f.setContent(k.content,{format:"raw"});f.selection.moveToBookmark(k.beforeBookmark);d.onUndo.dispatch(d,k)}return k},redo:function(){var i;if(e0||this.typing},hasRedo:function(){return e');q.replace(p,m);o.select(p,1)}return g}return d}l.create("tinymce.ForceBlocks",{ForceBlocks:function(m){var n=this,o=m.settings,p;n.editor=m;n.dom=m.dom;p=(o.forced_root_block||"p").toLowerCase();o.element=p.toUpperCase();m.onPreInit.add(n.setup,n)},setup:function(){var n=this,m=n.editor,p=m.settings,u=m.dom,o=m.selection,q=m.schema.getBlockElements();if(p.forced_root_block){function v(){var y=o.getStart(),t=m.getBody(),s,z,D,F,E,x,A,B=-16777215;if(!y||y.nodeType!==1){return}while(y!=t){if(q[y.nodeName]){return}y=y.parentNode}s=o.getRng();if(s.setStart){z=s.startContainer;D=s.startOffset;F=s.endContainer;E=s.endOffset}else{if(s.item){s=m.getDoc().body.createTextRange();s.moveToElementText(s.item(0))}tmpRng=s.duplicate();tmpRng.collapse(true);D=tmpRng.move("character",B)*-1;if(!tmpRng.collapsed){tmpRng=s.duplicate();tmpRng.collapse(false);E=(tmpRng.move("character",B)*-1)-D}}for(y=t.firstChild;y;y){if(y.nodeType===3||(y.nodeType==1&&!q[y.nodeName])){if(!x){x=u.create(p.forced_root_block);y.parentNode.insertBefore(x,y)}A=y;y=y.nextSibling;x.appendChild(A)}else{x=null;y=y.nextSibling}}if(s.setStart){s.setStart(z,D);s.setEnd(F,E);o.setRng(s)}else{try{s=m.getDoc().body.createTextRange();s.moveToElementText(t);s.collapse(true);s.moveStart("character",D);if(E>0){s.moveEnd("character",E)}s.select()}catch(C){}}m.nodeChanged()}m.onKeyUp.add(v);m.onClick.add(v)}if(p.force_br_newlines){if(c){m.onKeyPress.add(function(s,t){var x;if(t.keyCode==13&&o.getNode().nodeName!="LI"){o.setContent(' ',{format:"raw"});x=u.get("__");x.removeAttribute("id");o.select(x);o.collapse();return j.cancel(t)}})}}if(p.force_p_newlines){if(!c){m.onKeyPress.add(function(s,t){if(t.keyCode==13&&!t.shiftKey&&!n.insertPara(t)){j.cancel(t)}})}else{l.addUnload(function(){n._previousFormats=0});m.onKeyPress.add(function(s,t){n._previousFormats=0;if(t.keyCode==13&&!t.shiftKey&&s.selection.isCollapsed()&&p.keep_styles){n._previousFormats=k(s.selection.getStart())}});m.onKeyUp.add(function(t,y){if(y.keyCode==13&&!y.shiftKey){var x=t.selection.getStart(),s=n._previousFormats;if(!x.hasChildNodes()&&s){x=u.getParent(x,u.isBlock);if(x&&x.nodeName!="LI"){x.innerHTML="";if(n._previousFormats){x.appendChild(s.wrapper);s.inner.innerHTML="\uFEFF"}else{x.innerHTML="\uFEFF"}o.select(x,1);o.collapse(true);t.getDoc().execCommand("Delete",false,null);n._previousFormats=0}}}})}if(a){m.onKeyDown.add(function(s,t){if((t.keyCode==8||t.keyCode==46)&&!t.shiftKey){n.backspaceDelete(t,t.keyCode==8)}})}}if(l.isWebKit){function r(t){var s=o.getRng(),x,A=u.create("div",null," "),z,y=u.getViewPort(t.getWin()).h;s.insertNode(x=u.create("br"));s.setStartAfter(x);s.setEndAfter(x);o.setRng(s);if(o.getSel().focusNode==x.previousSibling){o.select(u.insertAfter(u.doc.createTextNode("\u00a0"),x));o.collapse(d)}u.insertAfter(A,x);z=u.getPos(A).y;u.remove(A);if(z>y){t.getWin().scrollTo(0,z)}}m.onKeyPress.add(function(s,t){if(t.keyCode==13&&(t.shiftKey||(p.force_br_newlines&&!u.getParent(o.getNode(),"h1,h2,h3,h4,h5,h6,ol,ul")))){r(s);j.cancel(t)}})}if(c){if(p.element!="P"){m.onKeyPress.add(function(s,t){n.lastElm=o.getNode().nodeName});m.onKeyUp.add(function(t,x){var z,y=o.getNode(),s=t.getBody();if(s.childNodes.length===1&&y.nodeName=="P"){y=u.rename(y,p.element);o.select(y);o.collapse();t.nodeChanged()}else{if(x.keyCode==13&&!x.shiftKey&&n.lastElm!="P"){z=u.getParent(y,"p");if(z){u.rename(z,p.element);t.nodeChanged()}}}})}}},getParentBlock:function(o){var m=this.dom;return m.getParent(o,m.isBlock)},insertPara:function(Q){var E=this,v=E.editor,M=v.dom,R=v.getDoc(),V=v.settings,F=v.selection.getSel(),G=F.getRangeAt(0),U=R.body;var J,K,H,O,N,q,o,u,z,m,C,T,p,x,I,L=M.getViewPort(v.getWin()),B,D,A;v.undoManager.beforeChange();J=R.createRange();J.setStart(F.anchorNode,F.anchorOffset);J.collapse(d);K=R.createRange();K.setStart(F.focusNode,F.focusOffset);K.collapse(d);H=J.compareBoundaryPoints(J.START_TO_END,K)<0;O=H?F.anchorNode:F.focusNode;N=H?F.anchorOffset:F.focusOffset;q=H?F.focusNode:F.anchorNode;o=H?F.focusOffset:F.anchorOffset;if(O===q&&/^(TD|TH)$/.test(O.nodeName)){if(O.firstChild.nodeName=="BR"){M.remove(O.firstChild)}if(O.childNodes.length==0){v.dom.add(O,V.element,null," ");T=v.dom.add(O,V.element,null," ")}else{I=O.innerHTML;O.innerHTML="";v.dom.add(O,V.element,null,I);T=v.dom.add(O,V.element,null," ")}G=R.createRange();G.selectNodeContents(T);G.collapse(1);v.selection.setRng(G);return g}if(O==U&&q==U&&U.firstChild&&v.dom.isBlock(U.firstChild)){O=q=O.firstChild;N=o=0;J=R.createRange();J.setStart(O,0);K=R.createRange();K.setStart(q,0)}if(!R.body.hasChildNodes()){R.body.appendChild(M.create("br"))}O=O.nodeName=="HTML"?R.body:O;O=O.nodeName=="BODY"?O.firstChild:O;q=q.nodeName=="HTML"?R.body:q;q=q.nodeName=="BODY"?q.firstChild:q;u=E.getParentBlock(O);z=E.getParentBlock(q);m=u?u.nodeName:V.element;if(I=E.dom.getParent(u,"li,pre")){if(I.nodeName=="LI"){return e(v.selection,E.dom,I)}return d}if(u&&(u.nodeName=="CAPTION"||/absolute|relative|fixed/gi.test(M.getStyle(u,"position",1)))){m=V.element;u=null}if(z&&(z.nodeName=="CAPTION"||/absolute|relative|fixed/gi.test(M.getStyle(u,"position",1)))){m=V.element;z=null}if(/(TD|TABLE|TH|CAPTION)/.test(m)||(u&&m=="DIV"&&/left|right/gi.test(M.getStyle(u,"float",1)))){m=V.element;u=z=null}C=(u&&u.nodeName==m)?u.cloneNode(0):v.dom.create(m);T=(z&&z.nodeName==m)?z.cloneNode(0):v.dom.create(m);T.removeAttribute("id");if(/^(H[1-6])$/.test(m)&&f(G,u)){T=v.dom.create(V.element)}I=p=O;do{if(I==U||I.nodeType==9||E.dom.isBlock(I)||/(TD|TABLE|TH|CAPTION)/.test(I.nodeName)){break}p=I}while((I=I.previousSibling?I.previousSibling:I.parentNode));I=x=q;do{if(I==U||I.nodeType==9||E.dom.isBlock(I)||/(TD|TABLE|TH|CAPTION)/.test(I.nodeName)){break}x=I}while((I=I.nextSibling?I.nextSibling:I.parentNode));if(p.nodeName==m){J.setStart(p,0)}else{J.setStartBefore(p)}J.setEnd(O,N);C.appendChild(J.cloneContents()||R.createTextNode(""));try{K.setEndAfter(x)}catch(P){}K.setStart(q,o);T.appendChild(K.cloneContents()||R.createTextNode(""));G=R.createRange();if(!p.previousSibling&&p.parentNode.nodeName==m){G.setStartBefore(p.parentNode)}else{if(J.startContainer.nodeName==m&&J.startOffset==0){G.setStartBefore(J.startContainer)}else{G.setStart(J.startContainer,J.startOffset)}}if(!x.nextSibling&&x.parentNode.nodeName==m){G.setEndAfter(x.parentNode)}else{G.setEnd(K.endContainer,K.endOffset)}G.deleteContents();if(b){v.getWin().scrollTo(0,L.y)}if(C.firstChild&&C.firstChild.nodeName==m){C.innerHTML=C.firstChild.innerHTML}if(T.firstChild&&T.firstChild.nodeName==m){T.innerHTML=T.firstChild.innerHTML}function S(y,s){var r=[],X,W,t;y.innerHTML="";if(V.keep_styles){W=s;do{if(/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(W.nodeName)){X=W.cloneNode(g);M.setAttrib(X,"id","");r.push(X)}}while(W=W.parentNode)}if(r.length>0){for(t=r.length-1,X=y;t>=0;t--){X=X.appendChild(r[t])}r[0].innerHTML=b?"\u00a0":" ";return r[0]}else{y.innerHTML=b?"\u00a0":" "}}if(M.isEmpty(C)){S(C,O)}if(M.isEmpty(T)){A=S(T,q)}if(b&&parseFloat(opera.version())<9.5){G.insertNode(C);G.insertNode(T)}else{G.insertNode(T);G.insertNode(C)}T.normalize();C.normalize();v.selection.select(T,true);v.selection.collapse(true);B=v.dom.getPos(T).y;if(BL.y+L.h){v.getWin().scrollTo(0,B1||ac==au){return ac}}}var am=V.selection.getRng();var aq=am.startContainer;var al=am.endContainer;if(aq!=al&&am.endOffset==0){var ap=an(aq,al);var ao=ap.nodeType==3?ap.length:ap.childNodes.length;am.setEnd(ap,ao)}return am}function Y(ao,au,ar,aq,am){var al=[],an=-1,at,aw=-1,ap=-1,av;O(ao.childNodes,function(ay,ax){if(ay.nodeName==="UL"||ay.nodeName==="OL"){an=ax;at=ay;return false}});O(ao.childNodes,function(ay,ax){if(ay.nodeName==="SPAN"&&c.getAttrib(ay,"data-mce-type")=="bookmark"){if(ay.id==au.id+"_start"){aw=ax}else{if(ay.id==au.id+"_end"){ap=ax}}}});if(an<=0||(awan)){O(a.grep(ao.childNodes),am);return 0}else{av=ar.cloneNode(S);O(a.grep(ao.childNodes),function(ay,ax){if((awan&&ax>an)){al.push(ay);ay.parentNode.removeChild(ay)}});if(awan){ao.insertBefore(av,at.nextSibling)}}aq.push(av);O(al,function(ax){av.appendChild(ax)});return av}}function aj(am,ao){var al=[],ap,an;ap=ai.inline||ai.block;an=c.create(ap);W(an);K.walk(am,function(aq){var ar;function at(au){var ax=au.nodeName.toLowerCase(),aw=au.parentNode.nodeName.toLowerCase(),av;if(g(ax,"br")){ar=0;if(ai.block){c.remove(au)}return}if(ai.wrapper&&x(au,Z,ah)){ar=0;return}if(ai.block&&!ai.wrapper&&G(ax)){au=c.rename(au,ap);W(au);al.push(au);ar=0;return}if(ai.selector){O(ad,function(ay){if("collapsed" in ay&&ay.collapsed!==ae){return}if(c.is(au,ay.selector)&&!b(au)){W(au,ay);av=true}});if(!ai.inline||av){ar=0;return}}if(d(ap,ax)&&d(aw,ap)&&!(au.nodeType===3&&au.nodeValue.length===1&&au.nodeValue.charCodeAt(0)===65279)){if(!ar){ar=an.cloneNode(S);au.parentNode.insertBefore(ar,au);al.push(ar)}ar.appendChild(au)}else{if(ax=="li"&&ao){ar=Y(au,ao,an,al,at)}else{ar=0;O(a.grep(au.childNodes),at);ar=0}}}O(aq,at)});if(ai.wrap_links===false){O(al,function(aq){function ar(aw){var av,au,at;if(aw.nodeName==="A"){au=an.cloneNode(S);al.push(au);at=a.grep(aw.childNodes);for(av=0;av1||!F(at))&&aq===0){c.remove(at,1);return}if(ai.inline||ai.wrapper){if(!ai.exact&&aq===1){at=ar(at)}O(ad,function(av){O(c.select(av.inline,at),function(ax){var aw;if(av.wrap_links===false){aw=ax.parentNode;do{if(aw.nodeName==="A"){return}}while(aw=aw.parentNode)}U(av,ah,ax,av.exact?ax:null)})});if(x(at.parentNode,Z,ah)){c.remove(at,1);at=0;return B}if(ai.merge_with_parents){c.getParent(at.parentNode,function(av){if(x(av,Z,ah)){c.remove(at,1);at=0;return B}})}if(at&&ai.merge_siblings!==false){at=u(C(at),at);at=u(at,C(at,B))}}})}if(ai){if(ac){X=c.createRng();X.setStartBefore(ac);X.setEndAfter(ac);aj(o(X,ad))}else{if(!ae||!ai.inline||c.select("td.mceSelected,th.mceSelected").length){var ak=V.selection.getNode();V.selection.setRng(ab());ag=q.getBookmark();aj(o(q.getRng(B),ad),ag);if(ai.styles&&(ai.styles.color||ai.styles.textDecoration)){a.walk(ak,I,"childNodes");I(ak)}q.moveToBookmark(ag);q.setRng(aa(q.getRng(B)));V.nodeChanged()}else{Q("apply",Z,ah)}}}}function A(Y,ah,ab){var ac=R(Y),aj=ac[0],ag,af,X;function aa(am){var al=am.startContainer,ar=am.startOffset,aq,ap,an,ao;if(al.nodeType==3&&ar>=al.nodeValue.length-1){al=al.parentNode;ar=s(al)+1}if(al.nodeType==1){an=al.childNodes;al=an[Math.min(ar,an.length-1)];aq=new t(al);if(ar>an.length-1){aq.next()}for(ap=aq.current();ap;ap=aq.next()){if(ap.nodeType==3&&!f(ap)){ao=c.create("a",null,E);ap.parentNode.insertBefore(ao,ap);am.setStart(ap,0);q.setRng(am);c.remove(ao);return}}}}function Z(ao){var an,am,al;an=a.grep(ao.childNodes);for(am=0,al=ac.length;am=0;Z--){if(P.apply[Z].name==Y){return true}}for(Z=P.remove.length-1;Z>=0;Z--){if(P.remove[Z].name==Y){return false}}return W(q.getNode())}aa=q.getNode();if(W(aa)){return B}X=q.getStart();if(X!=aa){if(W(X)){return B}}return S}function v(ad,ac){var aa,ab=[],Z={},Y,X,W;if(q.isCollapsed()){for(X=0;X=0;Y--){W=ad[X];if(P.remove[Y].name==W){Z[W]=true;break}}}for(Y=P.apply.length-1;Y>=0;Y--){for(X=0;X=0;X--){W=ac[X].selector;if(!W){return B}for(ab=Y.length-1;ab>=0;ab--){if(c.is(Y[ab],W)){return B}}}}return S}a.extend(this,{get:R,register:k,apply:T,remove:A,toggle:D,match:j,matchAll:v,matchNode:x,canApply:y});function h(W,X){if(g(W,X.inline)){return B}if(g(W,X.block)){return B}if(X.selector){return c.is(W,X.selector)}}function g(X,W){X=X||"";W=W||"";X=""+(X.nodeName||X);W=""+(W.nodeName||W);return X.toLowerCase()==W.toLowerCase()}function L(X,W){var Y=c.getStyle(X,W);if(W=="color"||W=="backgroundColor"){Y=c.toHex(Y)}if(W=="fontWeight"&&Y==700){Y="bold"}return""+Y}function r(W,X){if(typeof(W)!="string"){W=W(X)}else{if(X){W=W.replace(/%(\w+)/g,function(Z,Y){return X[Y]||Z})}}return W}function f(W){return W&&W.nodeType===3&&/^([\s\r\n]+|)$/.test(W.nodeValue)}function N(Y,X,W){var Z=c.create(X,W);Y.parentNode.insertBefore(Z,Y);Z.appendChild(Y);return Z}function o(W,ag,Z){var Y=W.startContainer,ad=W.startOffset,aj=W.endContainer,ae=W.endOffset,ai,af,ac;function ah(am,an,ak,al){var ao,ap;al=al||c.getRoot();for(;;){ao=am.parentNode;if(ao==al||(!ag[0].block_expand&&F(ao))){return am}for(ai=ao[an];ai&&ai!=am;ai=ai[ak]){if(ai.nodeType==1&&!H(ai)){return am}if(ai.nodeType==3&&!f(ai)){return am}}am=am.parentNode}return am}function ab(ak,al){if(al===p){al=ak.nodeType===3?ak.length:ak.childNodes.length}while(ak&&ak.hasChildNodes()){ak=ak.childNodes[al];if(ak){al=ak.nodeType===3?ak.length:ak.childNodes.length}}return{node:ak,offset:al}}if(Y.nodeType==1&&Y.hasChildNodes()){af=Y.childNodes.length-1;Y=Y.childNodes[ad>af?af:ad];if(Y.nodeType==3){ad=0}}if(aj.nodeType==1&&aj.hasChildNodes()){af=aj.childNodes.length-1;aj=aj.childNodes[ae>af?af:ae-1];if(aj.nodeType==3){ae=aj.nodeValue.length}}if(H(Y.parentNode)){Y=Y.parentNode}if(H(Y)){Y=Y.nextSibling||Y}if(H(aj.parentNode)){ae=c.nodeIndex(aj);aj=aj.parentNode}if(H(aj)&&aj.previousSibling){aj=aj.previousSibling;ae=aj.length}if(ag[0].inline){ac=ab(aj,ae);if(ac.node){while(ac.node&&ac.offset===0&&ac.node.previousSibling){ac=ab(ac.node.previousSibling)}if(ac.node&&ac.offset>0&&ac.node.nodeType===3&&ac.node.nodeValue.charAt(ac.offset-1)===" "){if(ac.offset>1){aj=ac.node;aj.splitText(ac.offset-1)}else{if(ac.node.previousSibling){aj=ac.node.previousSibling}}}}}if(ag[0].inline||ag[0].block_expand){Y=ah(Y,"firstChild","nextSibling");aj=ah(aj,"lastChild","previousSibling")}if(ag[0].selector&&ag[0].expand!==S&&!ag[0].inline){function aa(al,ak){var am,an,ap,ao;if(al.nodeType==3&&al.nodeValue.length==0&&al[ak]){al=al[ak]}am=m(al);for(an=0;anY?Y:Z]}return W}function Q(ad,Y,ac){var aa,X=P[ad],ae=P[ad=="apply"?"remove":"apply"];function af(){return P.apply.length||P.remove.length}function ab(){P.apply=[];P.remove=[]}function ag(ah){O(P.apply.reverse(),function(ai){T(ai.name,ai.vars,ah);if(ai.name==="forecolor"&&ai.vars.value){I(ah.parentNode)}});O(P.remove.reverse(),function(ai){A(ai.name,ai.vars,ah)});c.remove(ah,1);ab()}for(aa=X.length-1;aa>=0;aa--){if(X[aa].name==Y){return}}X.push({name:Y,vars:ac});for(aa=ae.length-1;aa>=0;aa--){if(ae[aa].name==Y){ae.splice(aa,1)}}if(af()){V.getDoc().execCommand("FontName",false,"mceinline");P.lastRng=q.getRng();O(c.select("font,span"),function(ai){var ah;if(b(ai)){ah=q.getBookmark();ag(ai);q.moveToBookmark(ah);V.nodeChanged()}});if(!P.isListening&&af()){P.isListening=true;function W(ai,aj){var ah=c.createRng();ag(ai);ah.setStart(aj,aj.nodeValue.length);ah.setEnd(aj,aj.nodeValue.length);q.setRng(ah);V.nodeChanged()}var Z=false;O("onKeyDown,onKeyUp,onKeyPress,onMouseUp".split(","),function(ah){V[ah].addToTop(function(ai,al){if(al.keyCode==13&&!al.shiftKey){Z=true;return}if(af()&&!a.dom.RangeUtils.compareRanges(P.lastRng,q.getRng())){var aj=false;O(c.select("font,span"),function(ao){var ap,an;if(b(ao)){aj=true;ap=ao.firstChild;while(ap&&ap.nodeType!=3){ap=ap.firstChild}if(ap){W(ao,ap)}else{c.remove(ao)}}});if(Z&&!aj){var ak=q.getNode();var am=ak;while(am&&am.nodeType!=3){am=am.firstChild}if(am){ak=am.parentNode;while(!F(ak)){ak=ak.parentNode}W(ak,am)}}if(al.type=="keyup"||al.type=="mouseup"){ab();Z=false}}})})}}}}})(tinymce);tinymce.onAddEditor.add(function(e,a){var d,h,g,c=a.settings;if(c.inline_styles){h=e.explode(c.font_size_style_values);function b(j,i){e.each(i,function(l,k){if(l){g.setStyle(j,k,l)}});g.rename(j,"span")}d={font:function(j,i){b(i,{backgroundColor:i.style.backgroundColor,color:i.color,fontFamily:i.face,fontSize:h[parseInt(i.size)-1]})},u:function(j,i){b(i,{textDecoration:"underline"})},strike:function(j,i){b(i,{textDecoration:"line-through"})}};function f(i,j){g=i.dom;if(c.convert_fonts_to_spans){e.each(g.select("font,u,strike",j.node),function(k){d[k.nodeName.toLowerCase()](a.dom,k)})}}a.onPreProcess.add(f);a.onSetContent.add(f);a.onInit.add(function(){a.selection.onSetContent.add(f)})}});
\ No newline at end of file
diff --git a/mod/tinymce/vendor/tinymce/jscripts/tiny_mce/tiny_mce_src.js b/mod/tinymce/vendor/tinymce/jscripts/tiny_mce/tiny_mce_src.js
index c1d47fcb7..358de47f2 100644
--- a/mod/tinymce/vendor/tinymce/jscripts/tiny_mce/tiny_mce_src.js
+++ b/mod/tinymce/vendor/tinymce/jscripts/tiny_mce/tiny_mce_src.js
@@ -5,9 +5,9 @@
var tinymce = {
majorVersion : '3',
- minorVersion : '4.2',
+ minorVersion : '4.6',
- releaseDate : '2011-04-07',
+ releaseDate : '2011-09-29',
_init : function() {
var t = this, d = document, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
@@ -20,6 +20,12 @@
t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
+ t.isIE7 = t.isIE && /MSIE [7]/.test(ua);
+
+ t.isIE8 = t.isIE && /MSIE [8]/.test(ua);
+
+ t.isIE9 = t.isIE && /MSIE [9]/.test(ua);
+
t.isGecko = !t.isWebKit && /Gecko/.test(ua);
t.isMac = ua.indexOf('Mac') != -1;
@@ -27,6 +33,8 @@
t.isAir = /adobeair/i.test(ua);
t.isIDevice = /(iPad|iPhone)/.test(ua);
+
+ t.isIOS5 = t.isIDevice && ua.match(/AppleWebKit\/(\d*)/)[1]>=534;
// TinyMCE .NET webcontrol might be setting the values for TinyMCE
if (win.tinyMCEPreInit) {
@@ -484,6 +492,7 @@
})(window);
+
tinymce.create('tinymce.util.Dispatcher', {
scope : null,
listeners : null,
@@ -542,7 +551,7 @@ tinymce.create('tinymce.util.Dispatcher', {
tinymce.create('tinymce.util.URI', {
URI : function(u, s) {
- var t = this, o, a, b;
+ var t = this, o, a, b, base_url;
// Trim whitespace
u = tinymce.trim(u);
@@ -550,8 +559,9 @@ tinymce.create('tinymce.util.Dispatcher', {
// Default settings
s = t.settings = s || {};
- // Strange app protocol or local anchor
- if (/^(mailto|tel|news|javascript|about|data):/i.test(u) || /^\s*#/.test(u)) {
+ // Strange app protocol that isn't http/https or local anchor
+ // For example: mailto,skype,tel etc.
+ if (/^([\w\-]+):([^\/]{2})/i.test(u) || /^\s*#/.test(u)) {
t.source = u;
return;
}
@@ -561,8 +571,10 @@ tinymce.create('tinymce.util.Dispatcher', {
u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
// Relative path http:// or protocol relative //path
- if (!/^\w*:?\/\//.test(u))
- u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);
+ if (!/^[\w-]*:?\/\//.test(u)) {
+ base_url = s.base_uri ? s.base_uri.path : new tinymce.util.URI(location.href).directory;
+ u = ((s.base_uri && s.base_uri.protocol) || 'http') + '://mce_host' + t.toAbsPath(base_url, u);
+ }
// Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
@@ -1024,12 +1036,155 @@ tinymce.create('static tinymce.util.XHR', {
}
});
}());
+(function(tinymce){
+ tinymce.VK = {
+ DELETE:46,
+ BACKSPACE:8
+
+ }
+
+})(tinymce);
+
+(function(tinymce) {
+ var VK = tinymce.VK, BACKSPACE = VK.BACKSPACE, DELETE = VK.DELETE;
+
+ function cleanupStylesWhenDeleting(ed) {
+ var dom = ed.dom, selection = ed.selection;
+
+ ed.onKeyDown.add(function(ed, e) {
+ var rng, blockElm, node, clonedSpan, isDelete;
+
+ isDelete = e.keyCode == DELETE;
+ if (isDelete || e.keyCode == BACKSPACE) {
+ e.preventDefault();
+ rng = selection.getRng();
+
+ // Find root block
+ blockElm = dom.getParent(rng.startContainer, dom.isBlock);
+
+ // On delete clone the root span of the next block element
+ if (isDelete)
+ blockElm = dom.getNext(blockElm, dom.isBlock);
+
+ // Locate root span element and clone it since it would otherwise get merged by the "apple-style-span" on delete/backspace
+ if (blockElm) {
+ node = blockElm.firstChild;
+
+ // Ignore empty text nodes
+ while (node.nodeType == 3 && node.nodeValue.length == 0)
+ node = node.nextSibling;
+
+ if (node && node.nodeName === 'SPAN') {
+ clonedSpan = node.cloneNode(false);
+ }
+ }
+
+ // Do the backspace/delete actiopn
+ ed.getDoc().execCommand(isDelete ? 'ForwardDelete' : 'Delete', false, null);
+
+ // Find all odd apple-style-spans
+ blockElm = dom.getParent(rng.startContainer, dom.isBlock);
+ tinymce.each(dom.select('span.Apple-style-span,font.Apple-style-span', blockElm), function(span) {
+ var bm = selection.getBookmark();
+
+ if (clonedSpan) {
+ dom.replace(clonedSpan.cloneNode(false), span, true);
+ } else {
+ dom.remove(span, true);
+ }
+
+ // Restore the selection
+ selection.moveToBookmark(bm);
+ });
+ }
+ });
+ };
+
+ function emptyEditorWhenDeleting(ed) {
+ ed.onKeyUp.add(function(ed, e) {
+ var keyCode = e.keyCode;
+
+ if (keyCode == DELETE || keyCode == BACKSPACE) {
+ if (ed.dom.isEmpty(ed.getBody())) {
+ ed.setContent('', {format : 'raw'});
+ ed.nodeChanged();
+ return;
+ }
+ }
+ });
+ };
+
+ function inputMethodFocus(ed) {
+ ed.dom.bind(ed.getDoc(), 'focusin', function() {
+ ed.selection.setRng(ed.selection.getRng());
+ });
+ };
+
+ function focusBody(ed) {
+ // Fix for a focus bug in FF 3.x where the body element
+ // wouldn't get proper focus if the user clicked on the HTML element
+ if (!Range.prototype.getClientRects) { // Detect getClientRects got introduced in FF 4
+ ed.onMouseDown.add(function(ed, e) {
+ if (e.target.nodeName === "HTML") {
+ var body = ed.getBody();
+
+ // Blur the body it's focused but not correctly focused
+ body.blur();
+
+ // Refocus the body after a little while
+ setTimeout(function() {
+ body.focus();
+ }, 0);
+ }
+ });
+ }
+ };
+
+ function selectControlElements(ed) {
+ ed.onClick.add(function(ed, e) {
+ e = e.target;
+
+ // Workaround for bug, http://bugs.webkit.org/show_bug.cgi?id=12250
+ // WebKit can't even do simple things like selecting an image
+ // Needs tobe the setBaseAndExtend or it will fail to select floated images
+ if (/^(IMG|HR)$/.test(e.nodeName))
+ ed.selection.getSel().setBaseAndExtent(e, 0, e, 1);
+
+ if (e.nodeName == 'A' && ed.dom.hasClass(e, 'mceItemAnchor'))
+ ed.selection.select(e);
+
+ ed.nodeChanged();
+ });
+ };
+
+ tinymce.create('tinymce.util.Quirks', {
+ Quirks: function(ed) {
+ // WebKit
+ if (tinymce.isWebKit) {
+ cleanupStylesWhenDeleting(ed);
+ emptyEditorWhenDeleting(ed);
+ inputMethodFocus(ed);
+ selectControlElements(ed);
+ }
+
+ // IE
+ if (tinymce.isIE) {
+ emptyEditorWhenDeleting(ed);
+ }
+
+ // Gecko
+ if (tinymce.isGecko) {
+ focusBody(ed);
+ }
+ }
+ });
+})(tinymce);
(function(tinymce) {
var namedEntities, baseEntities, reverseEntities,
- attrsCharsRegExp = /[&\"\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
+ attrsCharsRegExp = /[&<>\"\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
textCharsRegExp = /[<>&\u007E-\uD7FF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
rawCharsRegExp = /[<>&\"\']/g,
- entityRegExp = /&(#)?([\w]+);/g,
+ entityRegExp = /&(#x|#)?([\w]+);/g,
asciiMap = {
128 : "\u20AC", 130 : "\u201A", 131 : "\u0192", 132 : "\u201E", 133 : "\u2026", 134 : "\u2020",
135 : "\u2021", 136 : "\u02C6", 137 : "\u2030", 138 : "\u0160", 139 : "\u2039", 140 : "\u0152",
@@ -1040,7 +1195,7 @@ tinymce.create('static tinymce.util.XHR', {
// Raw entities
baseEntities = {
- '"' : '"',
+ '\"' : '"', // Needs to be escaped since the YUI compressor would otherwise break the code
"'" : ''',
'<' : '<',
'>' : '>',
@@ -1194,7 +1349,7 @@ tinymce.create('static tinymce.util.XHR', {
decode : function(text) {
return text.replace(entityRegExp, function(all, numeric, value) {
if (numeric) {
- value = parseInt(value);
+ value = parseInt(value, numeric.length === 2 ? 16 : 10);
// Support upper UTF
if (value > 0xFFFF) {
@@ -1221,10 +1376,10 @@ tinymce.html.Styles = function(settings, schema) {
settings = settings || {};
- encodingItems = '\\" \\\' \\; \\: ; : _'.split(' ');
+ encodingItems = '\\" \\\' \\; \\: ; : \uFEFF'.split(' ');
for (i = 0; i < encodingItems.length; i++) {
- encodingLookup[encodingItems[i]] = '_' + i;
- encodingLookup['_' + i] = encodingItems[i];
+ encodingLookup[encodingItems[i]] = '\uFEFF' + i;
+ encodingLookup['\uFEFF' + i] = encodingItems[i];
}
function toHex(match, r, g, b) {
@@ -1319,7 +1474,7 @@ tinymce.html.Styles = function(settings, schema) {
// It will also decode the \" \' if keep_slashes is set to fale or omitted
function decode(str, keep_slashes) {
if (isEncoded) {
- str = str.replace(/_[0-9]/g, function(str) {
+ str = str.replace(/\uFEFF[0-9]/g, function(str) {
return encodingLookup[str];
});
}
@@ -1332,7 +1487,7 @@ tinymce.html.Styles = function(settings, schema) {
if (css) {
// Encode \" \' % and ; and : inside strings so they don't interfere with the style parsing
- css = css.replace(/\\[\"\';:_]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) {
+ css = css.replace(/\\[\"\';:\uFEFF]/g, encode).replace(/\"[^\"]+\"|\'[^\']+\'/g, function(str) {
return str.replace(/[;:]/g, encode);
});
@@ -1399,7 +1554,7 @@ tinymce.html.Styles = function(settings, schema) {
var css = '', name, value;
function serializeStyles(name) {
- var styleList, i, l, name, value;
+ var styleList, i, l, value;
styleList = schema.styles[name];
if (styleList) {
@@ -1417,7 +1572,7 @@ tinymce.html.Styles = function(settings, schema) {
if (element_name && schema && schema.styles) {
// Serialize global styles and element specific styles
serializeStyles('*');
- serializeStyles(name);
+ serializeStyles(element_name);
} else {
// Output the styles in the order they are inside the object
for (name in styles) {
@@ -1434,8 +1589,8 @@ tinymce.html.Styles = function(settings, schema) {
};
(function(tinymce) {
- var transitional = {}, boolAttrMap, blockElementsMap, shortEndedElementsMap, nonEmptyElementsMap,
- whiteSpaceElementsMap, selfClosingElementsMap, makeMap = tinymce.makeMap, each = tinymce.each;
+ var transitional = {}, boolAttrMap, blockElementsMap, shortEndedElementsMap, nonEmptyElementsMap, customElementsMap = {},
+ defaultWhiteSpaceElementsMap, selfClosingElementsMap, makeMap = tinymce.makeMap, each = tinymce.each;
function split(str, delim) {
return str.split(delim || ',');
@@ -1596,14 +1751,14 @@ tinymce.html.Styles = function(settings, schema) {
'body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]'
);
- boolAttrMap = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected,preload,autoplay,loop,controls');
+ boolAttrMap = makeMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected,autoplay,loop,controls');
shortEndedElementsMap = makeMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,source');
- nonEmptyElementsMap = tinymce.extend(makeMap('td,th,iframe,video,object'), shortEndedElementsMap);
- whiteSpaceElementsMap = makeMap('pre,script,style');
+ nonEmptyElementsMap = tinymce.extend(makeMap('td,th,iframe,video,audio,object'), shortEndedElementsMap);
+ defaultWhiteSpaceElementsMap = makeMap('pre,script,style,textarea');
selfClosingElementsMap = makeMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr');
tinymce.html.Schema = function(settings) {
- var self = this, elements = {}, children = {}, patternElements = [], validStyles;
+ var self = this, elements = {}, children = {}, patternElements = [], validStyles, whiteSpaceElementsMap;
settings = settings || {};
@@ -1621,6 +1776,8 @@ tinymce.html.Styles = function(settings, schema) {
});
}
+ whiteSpaceElementsMap = settings.whitespace_elements ? makeMap(settings.whitespace_elements) : defaultWhiteSpaceElementsMap;
+
// Converts a wildcard expression string to a regexp for example *a will become /.*a/.
function patternToRegExp(str) {
return new RegExp('^' + str.replace(/([?+*])/g, '.$1') + '$');
@@ -1785,10 +1942,16 @@ tinymce.html.Styles = function(settings, schema) {
if (custom_elements) {
each(split(custom_elements), function(rule) {
var matches = customElementRegExp.exec(rule),
- cloneName = matches[1] === '~' ? 'span' : 'div',
+ inline = matches[1] === '~',
+ cloneName = inline ? 'span' : 'div',
name = matches[2];
children[name] = children[cloneName];
+ customElementsMap[name] = cloneName;
+
+ // If it's not marked as inline then add it to valid block elements
+ if (!inline)
+ blockElementsMap[name] = {};
// Add custom elements at span/div positions
each(children, function(element, child) {
@@ -1827,7 +1990,24 @@ tinymce.html.Styles = function(settings, schema) {
}
});
}
- }
+ };
+
+ function getElementRule(name) {
+ var element = elements[name], i;
+
+ // Exact match found
+ if (element)
+ return element;
+
+ // No exact match then try the patterns
+ i = patternElements.length;
+ while (i--) {
+ element = patternElements[i];
+
+ if (element.pattern.test(name))
+ return element;
+ }
+ };
if (!settings.valid_elements) {
// No valid elements defined then clone the elements from the transitional spec
@@ -1850,7 +2030,7 @@ tinymce.html.Styles = function(settings, schema) {
elements.img.attributesDefault = [{name: 'alt', value: ''}];
// Remove these if they are empty by default
- each(split('ol,ul,li,sub,sup,blockquote,tr,div,span,font,a,table,tbody'), function(name) {
+ each(split('ol,ul,sub,sup,blockquote,span,font,a,table,tbody,tr'), function(name) {
elements[name].removeEmpty = true;
});
@@ -1868,6 +2048,10 @@ tinymce.html.Styles = function(settings, schema) {
// Todo: Remove this when we fix list handling to be valid
addValidChildren('+ol[ul|ol],+ul[ul|ol]');
+ // If the user didn't allow span only allow internal spans
+ if (!getElementRule('span'))
+ addValidElements('span[!data-mce-type|*]');
+
// Delete invalid elements
if (settings.invalid_elements) {
tinymce.each(tinymce.explode(settings.invalid_elements), function(item) {
@@ -1910,21 +2094,10 @@ tinymce.html.Styles = function(settings, schema) {
return !!(parent && parent[child]);
};
- self.getElementRule = function(name) {
- var element = elements[name], i;
-
- // Exact match found
- if (element)
- return element;
-
- // No exact match then try the patterns
- i = patternElements.length;
- while (i--) {
- element = patternElements[i];
+ self.getElementRule = getElementRule;
- if (element.pattern.test(name))
- return element;
- }
+ self.getCustomElements = function() {
+ return customElementsMap;
};
self.addValidElements = addValidElements;
@@ -1958,10 +2131,10 @@ tinymce.html.Styles = function(settings, schema) {
});
self.parse = function(html) {
- var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name,
- shortEndedElements, fillAttrsMap, isShortEnded, validate, elementRule, isValidElement, attr, attribsValue,
+ var self = this, matches, index = 0, value, endRegExp, stack = [], attrList, i, text, name, isInternalElement, removeInternalElements,
+ shortEndedElements, fillAttrsMap, isShortEnded, validate, elementRule, isValidElement, attr, attribsValue, invalidPrefixRegExp,
validAttributesMap, validAttributePatterns, attributesRequired, attributesDefault, attributesForced, selfClosing,
- tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0, decode = tinymce.html.Entities.decode, fixSelfClosing;
+ tokenRegExp, attrRegExp, specialElements, attrValue, idCount = 0, decode = tinymce.html.Entities.decode, fixSelfClosing, isIE;
function processEndTag(name) {
var pos, i;
@@ -2010,7 +2183,10 @@ tinymce.html.Styles = function(settings, schema) {
selfClosing = schema.getSelfClosingElements();
fillAttrsMap = schema.getBoolAttrs();
validate = settings.validate;
+ removeInternalElements = settings.remove_internals;
fixSelfClosing = settings.fix_self_closing;
+ isIE = tinymce.isIE;
+ invalidPrefixRegExp = /^:/;
while (matches = tokenRegExp.exec(html)) {
// Text
@@ -2018,9 +2194,20 @@ tinymce.html.Styles = function(settings, schema) {
self.text(decode(html.substr(index, matches.index - index)));
if (value = matches[6]) { // End element
- processEndTag(value.toLowerCase());
+ value = value.toLowerCase();
+
+ // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+ if (isIE && invalidPrefixRegExp.test(value))
+ value = value.substr(1);
+
+ processEndTag(value);
} else if (value = matches[7]) { // Start element
value = value.toLowerCase();
+
+ // IE will add a ":" in front of elements it doesn't understand like custom elements or HTML5 elements
+ if (isIE && invalidPrefixRegExp.test(value))
+ value = value.substr(1);
+
isShortEnded = value in shortEndedElements;
// Is self closing tag for example an
after an open
@@ -2039,6 +2226,12 @@ tinymce.html.Styles = function(settings, schema) {
// Parse attributes
if (attribsValue = matches[8]) {
+ isInternalElement = attribsValue.indexOf('data-mce-type') !== -1; // Check if the element is an internal element
+
+ // If the element has internal attributes then remove it if we are told to do so
+ if (isInternalElement && removeInternalElements)
+ isValidElement = false;
+
attrList = [];
attrList.map = {};
@@ -2049,7 +2242,7 @@ tinymce.html.Styles = function(settings, schema) {
value = name in fillAttrsMap ? name : decode(value || val2 || val3 || ''); // Handle boolean attribute than value attribute
// Validate name and value
- if (validate && name.indexOf('data-') !== 0) {
+ if (validate && !isInternalElement && name.indexOf('data-') !== 0) {
attrRule = validAttributesMap[name];
// Find rule by pattern matching
@@ -2088,7 +2281,7 @@ tinymce.html.Styles = function(settings, schema) {
}
// Process attributes if validation is enabled
- if (validate) {
+ if (validate && !isInternalElement) {
attributesRequired = elementRule.attributesRequired;
attributesDefault = elementRule.attributesDefault;
attributesForced = elementRule.attributesForced;
@@ -2512,6 +2705,10 @@ tinymce.html.Styles = function(settings, schema) {
}
return true;
+ },
+
+ walk : function(prev) {
+ return walk(this, null, prev);
}
});
@@ -2695,7 +2892,7 @@ tinymce.html.Styles = function(settings, schema) {
self.parse = function(html, args) {
var parser, rootNode, node, nodes, i, l, fi, fl, list, name, validate,
blockElements, startWhiteSpaceRegExp, invalidChildren = [],
- endWhiteSpaceRegExp, allWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements;
+ endWhiteSpaceRegExp, allWhiteSpaceRegExp, whiteSpaceElements, children, nonEmptyElements, rootBlockName;
args = args || {};
matchedNodes = {};
@@ -2704,12 +2901,35 @@ tinymce.html.Styles = function(settings, schema) {
nonEmptyElements = schema.getNonEmptyElements();
children = schema.children;
validate = settings.validate;
+ rootBlockName = "forced_root_block" in args ? args.forced_root_block : settings.forced_root_block;
whiteSpaceElements = schema.getWhiteSpaceElements();
startWhiteSpaceRegExp = /^[ \t\r\n]+/;
endWhiteSpaceRegExp = /[ \t\r\n]+$/;
allWhiteSpaceRegExp = /[ \t\r\n]+/g;
+ function addRootBlocks() {
+ var node = rootNode.firstChild, next, rootBlockNode;
+
+ while (node) {
+ next = node.next;
+
+ if (node.type == 3 || (node.type == 1 && node.name !== 'p' && !blockElements[node.name] && !node.attr('data-mce-type'))) {
+ if (!rootBlockNode) {
+ // Create a new root block element
+ rootBlockNode = createNode(rootBlockName, 1);
+ rootNode.insert(rootBlockNode, node);
+ rootBlockNode.append(node);
+ } else
+ rootBlockNode.append(node);
+ } else {
+ rootBlockNode = null;
+ }
+
+ node = next;
+ };
+ };
+
function createNode(name, type) {
var node = new Node(name, type), list;
@@ -2897,35 +3117,28 @@ tinymce.html.Styles = function(settings, schema) {
}
}, schema);
- rootNode = node = new Node(settings.root_name, 11);
+ rootNode = node = new Node(args.context || settings.root_name, 11);
parser.parse(html);
- if (validate)
- fixInvalidChildren(invalidChildren);
-
- // Run node filters
- for (name in matchedNodes) {
- list = nodeFilters[name];
- nodes = matchedNodes[name];
-
- // Remove already removed children
- fi = nodes.length;
- while (fi--) {
- if (!nodes[fi].parent)
- nodes.splice(fi, 1);
- }
-
- for (i = 0, l = list.length; i < l; i++)
- list[i](nodes, name, args);
+ // Fix invalid children or report invalid children in a contextual parsing
+ if (validate && invalidChildren.length) {
+ if (!args.context)
+ fixInvalidChildren(invalidChildren);
+ else
+ args.invalid = true;
}
- // Run attribute filters
- for (i = 0, l = attributeFilters.length; i < l; i++) {
- list = attributeFilters[i];
+ // Wrap nodes in the root into block elements if the root is body
+ if (rootBlockName && rootNode.name == 'body')
+ addRootBlocks();
- if (list.name in matchedAttributes) {
- nodes = matchedAttributes[list.name];
+ // Run filters only when the contents is valid
+ if (!args.invalid) {
+ // Run node filters
+ for (name in matchedNodes) {
+ list = nodeFilters[name];
+ nodes = matchedNodes[name];
// Remove already removed children
fi = nodes.length;
@@ -2934,8 +3147,27 @@ tinymce.html.Styles = function(settings, schema) {
nodes.splice(fi, 1);
}
- for (fi = 0, fl = list.callbacks.length; fi < fl; fi++)
- list.callbacks[fi](nodes, list.name, args);
+ for (i = 0, l = list.length; i < l; i++)
+ list[i](nodes, name, args);
+ }
+
+ // Run attribute filters
+ for (i = 0, l = attributeFilters.length; i < l; i++) {
+ list = attributeFilters[i];
+
+ if (list.name in matchedAttributes) {
+ nodes = matchedAttributes[list.name];
+
+ // Remove already removed children
+ fi = nodes.length;
+ while (fi--) {
+ if (!nodes[fi].parent)
+ nodes.splice(fi, 1);
+ }
+
+ for (fi = 0, fl = list.callbacks.length; fi < fl; fi++)
+ list.callbacks[fi](nodes, list.name, args);
+ }
}
}
@@ -2950,6 +3182,9 @@ tinymce.html.Styles = function(settings, schema) {
var i, l = nodes.length, node, blockElements = schema.getBlockElements(),
nonEmptyElements = schema.getNonEmptyElements(), parent, prev, prevName;
+ // Remove brs from body element as well
+ blockElements.body = 1;
+
// Must loop forwards since it will otherwise remove all brs in
a
for (i = 0; i < l; i++) {
node = nodes[i];
@@ -2986,11 +3221,13 @@ tinymce.html.Styles = function(settings, schema) {
elementRule = schema.getElementRule(parent.name);
// Remove or padd the element depending on schema rule
- if (elementRule.removeEmpty)
- parent.remove();
- else if (elementRule.paddEmpty)
- parent.empty().append(new tinymce.html.Node('#text', 3)).value = '\u00a0';
- }
+ if (elementRule) {
+ if (elementRule.removeEmpty)
+ parent.remove();
+ else if (elementRule.paddEmpty)
+ parent.empty().append(new tinymce.html.Node('#text', 3)).value = '\u00a0';
+ }
+ }
}
}
}
@@ -3247,7 +3484,7 @@ tinymce.html.Writer = function(settings) {
},
DOMUtils : function(d, s) {
- var t = this, globalStyle;
+ var t = this, globalStyle, name;
t.doc = d;
t.win = window;
@@ -3278,7 +3515,7 @@ tinymce.html.Writer = function(settings) {
}
}
- if (isIE) {
+ if (isIE && s.schema) {
// Add missing HTML 4/5 elements to IE
('abbr article aside audio canvas ' +
'details figcaption figure footer ' +
@@ -3287,6 +3524,11 @@ tinymce.html.Writer = function(settings) {
'time video').replace(/\w+/g, function(name) {
d.createElement(name);
});
+
+ // Create all custom elements
+ for (name in s.schema.getCustomElements()) {
+ d.createElement(name);
+ }
}
tinymce.addUnload(t.destroy, t);
@@ -3691,12 +3933,12 @@ tinymce.html.Writer = function(settings) {
},
getAttrib : function(e, n, dv) {
- var v, t = this;
+ var v, t = this, undef;
e = t.get(e);
if (!e || e.nodeType !== 1)
- return false;
+ return dv === undef ? false : dv;
if (!is(dv))
dv = '';
@@ -3808,7 +4050,7 @@ tinymce.html.Writer = function(settings) {
}
}
- return (v !== undefined && v !== null && v !== '') ? '' + v : dv;
+ return (v !== undef && v !== null && v !== '') ? '' + v : dv;
},
getPos : function(n, ro) {
@@ -3818,14 +4060,17 @@ tinymce.html.Writer = function(settings) {
ro = ro || d.body;
if (n) {
- // Use getBoundingClientRect on IE, Opera has it but it's not perfect
- if (isIE && !t.stdMode) {
+ // Use getBoundingClientRect if it exists since it's faster than looping offset nodes
+ if (n.getBoundingClientRect) {
n = n.getBoundingClientRect();
e = t.boxModel ? d.documentElement : d.body;
- x = t.getStyle(t.select('html')[0], 'borderWidth'); // Remove border
- x = (x == 'medium' || t.boxModel && !t.isIE6) && 2 || x;
- return {x : n.left + e.scrollLeft - x, y : n.top + e.scrollTop - x};
+ // Add scroll offsets from documentElement or body since IE with the wrong box model will use d.body and so do WebKit
+ // Also remove the body/documentelement clientTop/clientLeft on IE 6, 7 since they offset the position
+ x = n.left + (d.documentElement.scrollLeft || d.body.scrollLeft) - e.clientTop;
+ y = n.top + (d.documentElement.scrollTop || d.body.scrollTop) - e.clientLeft;
+
+ return {x : x, y : y};
}
r = n;
@@ -4280,7 +4525,7 @@ tinymce.html.Writer = function(settings) {
},
isEmpty : function(node, elements) {
- var self = this, i, attributes, type, walker, name;
+ var self = this, i, attributes, type, walker, name, parentNode;
node = node.firstChild;
if (node) {
@@ -4296,15 +4541,23 @@ tinymce.html.Writer = function(settings) {
continue;
// Keep empty elements like
- if (elements && elements[node.nodeName.toLowerCase()])
+ name = node.nodeName.toLowerCase();
+ if (elements && elements[name]) {
+ // Ignore single BR elements in blocks like
+ parentNode = node.parentNode;
+ if (name === 'br' && self.isBlock(parentNode) && parentNode.firstChild === node && parentNode.lastChild === node) {
+ continue;
+ }
+
return false;
+ }
- // Keep elements with data attributes or name attribute like
+ // Keep elements with data-bookmark attributes or name attribute like
attributes = self.getAttribs(node);
i = node.attributes.length;
while (i--) {
name = node.attributes[i].nodeName;
- if (name === "name" || name.indexOf('data-') === 0)
+ if (name === "name" || name === 'data-mce-bookmark')
return false;
}
}
@@ -4338,7 +4591,7 @@ tinymce.html.Writer = function(settings) {
},
nodeIndex : function(node, normalized) {
- var idx = 0, lastNodeType, lastNode, nodeType, nodeValueExists;
+ var idx = 0, lastNodeType, lastNode, nodeType;
if (node) {
for (lastNodeType = node.nodeType, node = node.previousSibling, lastNode = node; node; node = node.previousSibling) {
@@ -4346,11 +4599,7 @@ tinymce.html.Writer = function(settings) {
// Normalize text nodes
if (normalized && nodeType == 3) {
- // ensure that text nodes that have been removed are handled correctly in Internet Explorer.
- // (the nodeValue attribute will not exist, and will error here).
- nodeValueExists = false;
- try {nodeValueExists = node.nodeValue.length} catch (c) {}
- if (nodeType == lastNodeType || !nodeValueExists)
+ if (nodeType == lastNodeType || !node.nodeValue.length)
continue;
}
idx++;
@@ -5193,11 +5442,97 @@ tinymce.html.Writer = function(settings) {
(function() {
function Selection(selection) {
- var t = this, invisibleChar = '\uFEFF', range, lastIERng, dom = selection.dom, TRUE = true, FALSE = false;
+ var self = this, dom = selection.dom, TRUE = true, FALSE = false;
+
+ function getPosition(rng, start) {
+ var checkRng, startIndex = 0, endIndex, inside,
+ children, child, offset, index, position = -1, parent;
+
+ // Setup test range, collapse it and get the parent
+ checkRng = rng.duplicate();
+ checkRng.collapse(start);
+ parent = checkRng.parentElement();
+
+ // Check if the selection is within the right document
+ if (parent.ownerDocument !== selection.dom.doc)
+ return;
+
+ // IE will report non editable elements as it's parent so look for an editable one
+ while (parent.contentEditable === "false") {
+ parent = parent.parentNode;
+ }
+
+ // If parent doesn't have any children then return that we are inside the element
+ if (!parent.hasChildNodes()) {
+ return {node : parent, inside : 1};
+ }
+
+ // Setup node list and endIndex
+ children = parent.children;
+ endIndex = children.length - 1;
+
+ // Perform a binary search for the position
+ while (startIndex <= endIndex) {
+ index = Math.floor((startIndex + endIndex) / 2);
+
+ // Move selection to node and compare the ranges
+ child = children[index];
+ checkRng.moveToElementText(child);
+ position = checkRng.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', rng);
+
+ // Before/after or an exact match
+ if (position > 0) {
+ endIndex = index - 1;
+ } else if (position < 0) {
+ startIndex = index + 1;
+ } else {
+ return {node : child};
+ }
+ }
+
+ // Check if child position is before or we didn't find a position
+ if (position < 0) {
+ // No element child was found use the parent element and the offset inside that
+ if (!child) {
+ checkRng.moveToElementText(parent);
+ checkRng.collapse(true);
+ child = parent;
+ inside = true;
+ } else
+ checkRng.collapse(false);
+
+ checkRng.setEndPoint(start ? 'EndToStart' : 'EndToEnd', rng);
+
+ // Fix for edge case:
..
ab|c
+ if (checkRng.compareEndPoints(start ? 'StartToStart' : 'StartToEnd', rng) > 0) {
+ checkRng = rng.duplicate();
+ checkRng.collapse(start);
+
+ offset = -1;
+ while (parent == checkRng.parentElement()) {
+ if (checkRng.move('character', -1) == 0)
+ break;
+
+ offset++;
+ }
+ }
+
+ offset = offset || checkRng.text.replace('\r\n', ' ').length;
+ } else {
+ // Child position is after the selection endpoint
+ checkRng.collapse(true);
+ checkRng.setEndPoint(start ? 'StartToStart' : 'StartToEnd', rng);
+
+ // Get the length of the text to find where the endpoint is relative to it's container
+ offset = checkRng.text.replace('\r\n', ' ').length;
+ }
+
+ return {node : child, position : position, offset : offset, inside : inside};
+ };
// Returns a W3C DOM compatible range object by using the IE Range API
function getRange() {
- var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed;
+ var ieRange = selection.getRng(), domRange = dom.createRng(), element, collapsed, tmpRange, element2, bookmark, fail;
// If selection is outside the current document just return an empty range
element = ieRange.item ? ieRange.item(0) : ieRange.parentElement();
@@ -5206,147 +5541,294 @@ tinymce.html.Writer = function(settings) {
collapsed = selection.isCollapsed();
- // Handle control selection or text selection of a image
- if (ieRange.item || !element.hasChildNodes()) {
- if (collapsed) {
- domRange.setStart(element, 0);
- domRange.setEnd(element, 0);
- } else {
- domRange.setStart(element.parentNode, dom.nodeIndex(element));
- domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
- }
+ // Handle control selection
+ if (ieRange.item) {
+ domRange.setStart(element.parentNode, dom.nodeIndex(element));
+ domRange.setEnd(domRange.startContainer, domRange.startOffset + 1);
return domRange;
}
function findEndPoint(start) {
- var marker, container, offset, nodes, startIndex = 0, endIndex, index, parent, checkRng, position;
-
- // Setup temp range and collapse it
- checkRng = ieRange.duplicate();
- checkRng.collapse(start);
+ var endPoint = getPosition(ieRange, start), container, offset, textNodeOffset = 0, sibling, undef, nodeValue;
- // Create marker and insert it at the end of the endpoints parent
- marker = dom.create('a');
- parent = checkRng.parentElement();
+ container = endPoint.node;
+ offset = endPoint.offset;
- // If parent doesn't have any children then set the container to that parent and the index to 0
- if (!parent.hasChildNodes()) {
- domRange[start ? 'setStart' : 'setEnd'](parent, 0);
+ if (endPoint.inside && !container.hasChildNodes()) {
+ domRange[start ? 'setStart' : 'setEnd'](container, 0);
return;
}
- parent.appendChild(marker);
- checkRng.moveToElementText(marker);
- position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng);
- if (position > 0) {
- // The position is after the end of the parent element.
- // This is the case where IE puts the caret to the left edge of a table.
- domRange[start ? 'setStartAfter' : 'setEndAfter'](parent);
- dom.remove(marker);
+ if (offset === undef) {
+ domRange[start ? 'setStartBefore' : 'setEndAfter'](container);
return;
}
- // Setup node list and endIndex
- nodes = tinymce.grep(parent.childNodes);
- endIndex = nodes.length - 1;
- // Perform a binary search for the position
- while (startIndex <= endIndex) {
- index = Math.floor((startIndex + endIndex) / 2);
-
- // Insert marker and check it's position relative to the selection
- parent.insertBefore(marker, nodes[index]);
- checkRng.moveToElementText(marker);
- position = ieRange.compareEndPoints(start ? 'StartToStart' : 'EndToEnd', checkRng);
- if (position > 0) {
- // Marker is to the right
- startIndex = index + 1;
- } else if (position < 0) {
- // Marker is to the left
- endIndex = index - 1;
- } else {
- // Maker is where we are
- found = true;
- break;
+ if (endPoint.position < 0) {
+ sibling = endPoint.inside ? container.firstChild : container.nextSibling;
+
+ if (!sibling) {
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](container);
+ return;
}
- }
- // Setup container
- container = position > 0 || index == 0 ? marker.nextSibling : marker.previousSibling;
+ if (!offset) {
+ if (sibling.nodeType == 3)
+ domRange[start ? 'setStart' : 'setEnd'](sibling, 0);
+ else
+ domRange[start ? 'setStartBefore' : 'setEndBefore'](sibling);
- // Handle element selection
- if (container.nodeType == 1) {
- dom.remove(marker);
+ return;
+ }
- // Find offset and container
- offset = dom.nodeIndex(container);
- container = container.parentNode;
+ // Find the text node and offset
+ while (sibling) {
+ nodeValue = sibling.nodeValue;
+ textNodeOffset += nodeValue.length;
- // Move the offset if we are setting the end or the position is after an element
- if (!start || index > 0)
- offset++;
+ // We are at or passed the position we where looking for
+ if (textNodeOffset >= offset) {
+ container = sibling;
+ textNodeOffset -= offset;
+ textNodeOffset = nodeValue.length - textNodeOffset;
+ break;
+ }
+
+ sibling = sibling.nextSibling;
+ }
} else {
- // Calculate offset within text node
- if (position > 0 || index == 0) {
- checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange);
- offset = checkRng.text.length;
- } else {
- checkRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', ieRange);
- offset = container.nodeValue.length - checkRng.text.length;
+ // Find the text node and offset
+ sibling = container.previousSibling;
+
+ if (!sibling)
+ return domRange[start ? 'setStartBefore' : 'setEndBefore'](container);
+
+ // If there isn't any text to loop then use the first position
+ if (!offset) {
+ if (container.nodeType == 3)
+ domRange[start ? 'setStart' : 'setEnd'](sibling, container.nodeValue.length);
+ else
+ domRange[start ? 'setStartAfter' : 'setEndAfter'](sibling);
+
+ return;
}
- dom.remove(marker);
+ while (sibling) {
+ textNodeOffset += sibling.nodeValue.length;
+
+ // We are at or passed the position we where looking for
+ if (textNodeOffset >= offset) {
+ container = sibling;
+ textNodeOffset -= offset;
+ break;
+ }
+
+ sibling = sibling.previousSibling;
+ }
}
- domRange[start ? 'setStart' : 'setEnd'](container, offset);
+ domRange[start ? 'setStart' : 'setEnd'](container, textNodeOffset);
};
- // Find start point
- findEndPoint(true);
+ try {
+ // Find start point
+ findEndPoint(true);
+
+ // Find end point if needed
+ if (!collapsed)
+ findEndPoint();
+ } catch (ex) {
+ // IE has a nasty bug where text nodes might throw "invalid argument" when you
+ // access the nodeValue or other properties of text nodes. This seems to happend when
+ // text nodes are split into two nodes by a delete/backspace call. So lets detect it and try to fix it.
+ if (ex.number == -2147024809) {
+ // Get the current selection
+ bookmark = self.getBookmark(2);
+
+ // Get start element
+ tmpRange = ieRange.duplicate();
+ tmpRange.collapse(true);
+ element = tmpRange.parentElement();
+
+ // Get end element
+ if (!collapsed) {
+ tmpRange = ieRange.duplicate();
+ tmpRange.collapse(false);
+ element2 = tmpRange.parentElement();
+ element2.innerHTML = element2.innerHTML;
+ }
+
+ // Remove the broken elements
+ element.innerHTML = element.innerHTML;
+
+ // Restore the selection
+ self.moveToBookmark(bookmark);
- // Find end point if needed
- if (!collapsed)
- findEndPoint();
+ // Since the range has moved we need to re-get it
+ ieRange = selection.getRng();
+
+ // Find start point
+ findEndPoint(true);
+
+ // Find end point if needed
+ if (!collapsed)
+ findEndPoint();
+ } else
+ throw ex; // Throw other errors
+ }
return domRange;
};
- this.addRange = function(rng) {
- var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body;
-
- function setEndPoint(start) {
- var container, offset, marker, tmpRng, nodes;
+ this.getBookmark = function(type) {
+ var rng = selection.getRng(), start, end, bookmark = {};
- marker = dom.create('a');
- container = start ? startContainer : endContainer;
- offset = start ? startOffset : endOffset;
- tmpRng = ieRng.duplicate();
+ function getIndexes(node) {
+ var node, parent, root, children, i, indexes = [];
- if (container == doc || container == doc.documentElement) {
- container = body;
- offset = 0;
- }
+ parent = node.parentNode;
+ root = dom.getRoot().parentNode;
- if (container.nodeType == 3) {
- container.parentNode.insertBefore(marker, container);
- tmpRng.moveToElementText(marker);
- tmpRng.moveStart('character', offset);
- dom.remove(marker);
- ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
- } else {
- nodes = container.childNodes;
+ while (parent != root) {
+ children = parent.children;
- if (nodes.length) {
- if (offset >= nodes.length) {
- dom.insertAfter(marker, nodes[nodes.length - 1]);
- } else {
- container.insertBefore(marker, nodes[offset]);
+ i = children.length;
+ while (i--) {
+ if (node === children[i]) {
+ indexes.push(i);
+ break;
+ }
+ }
+
+ node = parent;
+ parent = parent.parentNode;
+ }
+
+ return indexes;
+ };
+
+ function getBookmarkEndPoint(start) {
+ var position;
+
+ position = getPosition(rng, start);
+ if (position) {
+ return {
+ position : position.position,
+ offset : position.offset,
+ indexes : getIndexes(position.node),
+ inside : position.inside
+ };
+ }
+ };
+
+ // Non ubstructive bookmark
+ if (type === 2) {
+ // Handle text selection
+ if (!rng.item) {
+ bookmark.start = getBookmarkEndPoint(true);
+
+ if (!selection.isCollapsed())
+ bookmark.end = getBookmarkEndPoint();
+ } else
+ bookmark.start = {ctrl : true, indexes : getIndexes(rng.item(0))};
+ }
+
+ return bookmark;
+ };
+
+ this.moveToBookmark = function(bookmark) {
+ var rng, body = dom.doc.body;
+
+ function resolveIndexes(indexes) {
+ var node, i, idx, children;
+
+ node = dom.getRoot();
+ for (i = indexes.length - 1; i >= 0; i--) {
+ children = node.children;
+ idx = indexes[i];
+
+ if (idx <= children.length - 1) {
+ node = children[idx];
+ }
+ }
+
+ return node;
+ };
+
+ function setBookmarkEndPoint(start) {
+ var endPoint = bookmark[start ? 'start' : 'end'], moveLeft, moveRng, undef;
+
+ if (endPoint) {
+ moveLeft = endPoint.position > 0;
+
+ moveRng = body.createTextRange();
+ moveRng.moveToElementText(resolveIndexes(endPoint.indexes));
+
+ offset = endPoint.offset;
+ if (offset !== undef) {
+ moveRng.collapse(endPoint.inside || moveLeft);
+ moveRng.moveStart('character', moveLeft ? -offset : offset);
+ } else
+ moveRng.collapse(start);
+
+ rng.setEndPoint(start ? 'StartToStart' : 'EndToStart', moveRng);
+
+ if (start)
+ rng.collapse(true);
+ }
+ };
+
+ if (bookmark.start) {
+ if (bookmark.start.ctrl) {
+ rng = body.createControlRange();
+ rng.addElement(resolveIndexes(bookmark.start.indexes));
+ rng.select();
+ } else {
+ rng = body.createTextRange();
+ setBookmarkEndPoint(true);
+ setBookmarkEndPoint();
+ rng.select();
+ }
+ }
+ };
+
+ this.addRange = function(rng) {
+ var ieRng, ctrlRng, startContainer, startOffset, endContainer, endOffset, doc = selection.dom.doc, body = doc.body;
+
+ function setEndPoint(start) {
+ var container, offset, marker, tmpRng, nodes;
+
+ marker = dom.create('a');
+ container = start ? startContainer : endContainer;
+ offset = start ? startOffset : endOffset;
+ tmpRng = ieRng.duplicate();
+
+ if (container == doc || container == doc.documentElement) {
+ container = body;
+ offset = 0;
+ }
+
+ if (container.nodeType == 3) {
+ container.parentNode.insertBefore(marker, container);
+ tmpRng.moveToElementText(marker);
+ tmpRng.moveStart('character', offset);
+ dom.remove(marker);
+ ieRng.setEndPoint(start ? 'StartToStart' : 'EndToEnd', tmpRng);
+ } else {
+ nodes = container.childNodes;
+
+ if (nodes.length) {
+ if (offset >= nodes.length) {
+ dom.insertAfter(marker, nodes[nodes.length - 1]);
+ } else {
+ container.insertBefore(marker, nodes[offset]);
}
tmpRng.moveToElementText(marker);
} else {
// Empty node selection for example
|
- marker = doc.createTextNode(invisibleChar);
+ marker = doc.createTextNode('\uFEFF');
container.appendChild(marker);
tmpRng.moveToElementText(marker.parentNode);
tmpRng.collapse(TRUE);
@@ -5357,9 +5839,6 @@ tinymce.html.Writer = function(settings) {
}
}
- // Destroy cached range
- this.destroy();
-
// Setup some shorter versions
startContainer = rng.startContainer;
startOffset = rng.startOffset;
@@ -5389,33 +5868,8 @@ tinymce.html.Writer = function(settings) {
ieRng.select();
};
- this.getRangeAt = function() {
- // Setup new range if the cache is empty
- if (!range || !tinymce.dom.RangeUtils.compareRanges(lastIERng, selection.getRng())) {
- range = getRange();
-
- // Store away text range for next call
- lastIERng = selection.getRng();
- }
-
- // IE will say that the range is equal then produce an invalid argument exception
- // if you perform specific operations in a keyup event. For example Ctrl+Del.
- // This hack will invalidate the range cache if the exception occurs
- try {
- range.startContainer.nextSibling;
- } catch (ex) {
- range = getRange();
- lastIERng = null;
- }
-
- // Return cached range
- return range;
- };
-
- this.destroy = function() {
- // Destroy cached range and last IE range to avoid memory leaks
- lastIERng = range = null;
- };
+ // Expose range method
+ this.getRangeAt = getRange;
};
// Expose the selection object
@@ -6734,7 +7188,7 @@ window.tinymce.dom.Sizzle = Sizzle;
return;
try {
- // If IE is used, use the trick by Diego Perini
+ // If IE is used, use the trick by Diego Perini licensed under MIT by request to the author.
// http://javascript.nwbox.com/IEContentLoaded/
doc.documentElement.doScroll("left");
} catch (ex) {
@@ -6926,6 +7380,13 @@ window.tinymce.dom.Sizzle = Sizzle;
tinymce.addUnload(t.destroy, t);
},
+ setCursorLocation: function(node, offset) {
+ var t = this; var r = t.dom.createRng();
+ r.setStart(node, offset);
+ r.setEnd(node, offset);
+ t.setRng(r);
+ t.collapse(false);
+ },
getContent : function(s) {
var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
@@ -6933,6 +7394,7 @@ window.tinymce.dom.Sizzle = Sizzle;
wb = wa = '';
s.get = true;
s.format = s.format || 'html';
+ s.forced_root_block = '';
t.onBeforeGetContent.dispatch(t, s);
if (s.format == 'text')
@@ -6943,9 +7405,13 @@ window.tinymce.dom.Sizzle = Sizzle;
if (n)
e.appendChild(n);
- } else if (is(r.item) || is(r.htmlText))
- e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
- else
+ } else if (is(r.item) || is(r.htmlText)) {
+ // IE will produce invalid markup if elements are present that
+ // it doesn't understand like custom elements or HTML5 elements.
+ // Adding a BR in front of the contents and then remoiving it seems to fix it though.
+ e.innerHTML = ' ' + (r.item ? r.item(0).outerHTML : r.htmlText);
+ e.removeChild(e.firstChild);
+ } else
e.innerHTML = r.toString();
// Keep whitespace before and after
@@ -7017,7 +7483,12 @@ window.tinymce.dom.Sizzle = Sizzle;
// Remove the caret position
self.dom.remove('__caret');
- self.setRng(rng);
+
+ try {
+ self.setRng(rng);
+ } catch (ex) {
+ // Might fail on Opera for some odd reason
+ }
} else {
if (rng.item) {
// Delete content and get caret text selection
@@ -7025,7 +7496,12 @@ window.tinymce.dom.Sizzle = Sizzle;
rng = self.getRng();
}
- rng.pasteHTML(content);
+ // Explorer removes spaces from the beginning of pasted contents
+ if (/^\s+/.test(content)) {
+ rng.pasteHTML('_' + content);
+ self.dom.remove('__mce_tmp');
+ } else
+ rng.pasteHTML(content);
}
// Dispatch set content event
@@ -7153,6 +7629,9 @@ window.tinymce.dom.Sizzle = Sizzle;
return bookmark;
};
+ if (t.tridentSel)
+ return t.tridentSel.getBookmark(type);
+
return getLocation();
}
@@ -7225,10 +7704,6 @@ window.tinymce.dom.Sizzle = Sizzle;
moveToBookmark : function(bookmark) {
var t = this, dom = t.dom, marker1, marker2, rng, root, startContainer, endContainer, startOffset, endOffset;
- // Clear selection cache
- if (t.tridentSel)
- t.tridentSel.destroy();
-
if (bookmark) {
if (bookmark.start) {
rng = dom.createRng();
@@ -7268,6 +7743,9 @@ window.tinymce.dom.Sizzle = Sizzle;
return true;
};
+ if (t.tridentSel)
+ return t.tridentSel.moveToBookmark(bookmark);
+
if (setEndPoint(true) && setEndPoint()) {
t.setRng(rng);
}
@@ -7603,14 +8081,84 @@ window.tinymce.dom.Sizzle = Sizzle;
return bl;
},
+ normalize : function() {
+ var self = this, rng, normalized;
+
+ // Normalize only on non IE browsers for now
+ if (tinymce.isIE)
+ return;
+
+ function normalizeEndPoint(start) {
+ var container, offset, walker, dom = self.dom, body = dom.getRoot(), node;
+
+ container = rng[(start ? 'start' : 'end') + 'Container'];
+ offset = rng[(start ? 'start' : 'end') + 'Offset'];
+
+ // If the container is a document move it to the body element
+ if (container.nodeType === 9) {
+ container = container.body;
+ offset = 0;
+ }
+
+ // If the container is body try move it into the closest text node or position
+ // TODO: Add more logic here to handle element selection cases
+ if (container === body) {
+ // Resolve the index
+ if (container.hasChildNodes()) {
+ container = container.childNodes[Math.min(!start && offset > 0 ? offset - 1 : offset, container.childNodes.length - 1)];
+ offset = 0;
+
+ // Don't walk into elements that doesn't have any child nodes like a IMG
+ if (container.hasChildNodes()) {
+ // Walk the DOM to find a text node to place the caret at or a BR
+ node = container;
+ walker = new tinymce.dom.TreeWalker(container, body);
+ do {
+ // Found a text node use that position
+ if (node.nodeType === 3) {
+ offset = start ? 0 : node.nodeValue.length - 1;
+ container = node;
+ break;
+ }
+
+ // Found a BR element that we can place the caret before
+ if (node.nodeName === 'BR') {
+ offset = dom.nodeIndex(node);
+ container = node.parentNode;
+ break;
+ }
+ } while (node = (start ? walker.next() : walker.prev()));
+
+ normalized = true;
+ }
+ }
+ }
+
+ // Set endpoint if it was normalized
+ if (normalized)
+ rng['set' + (start ? 'Start' : 'End')](container, offset);
+ };
+
+ rng = self.getRng();
+
+ // Normalize the end points
+ normalizeEndPoint(true);
+
+ if (rng.collapsed)
+ normalizeEndPoint();
+
+ // Set the selection if it was normalized
+ if (normalized) {
+ //console.log(self.dom.dumpRng(rng));
+ self.setRng(rng);
+ }
+ },
+
destroy : function(s) {
var t = this;
t.win = null;
- if (t.tridentSel)
- t.tridentSel.destroy();
-
// Manual destroy then remove unload handler
if (!s)
tinymce.removeUnload(t.destroy);
@@ -7876,7 +8424,7 @@ window.tinymce.dom.Sizzle = Sizzle;
// Explorer won't clone contents of script and style and the
// selected index of select elements are cleared on a clone operation.
- if (isIE && dom.select('script,style,select').length > 0) {
+ if (isIE && dom.select('script,style,select,map').length > 0) {
content = node.innerHTML;
node = node.cloneNode(false);
dom.setHTML(node, content);
@@ -8527,6 +9075,7 @@ tinymce.dom.TreeWalker = function(start_node, root_node) {
}
});
})(tinymce);
+
(function(tinymce) {
// Shorten class names
var DOM = tinymce.DOM, is = tinymce.is;
@@ -9158,8 +9707,7 @@ tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
l = DOM.encode(s.label || '');
h = '';
-
- if (s.image)
+ if (s.image && !(this.editor &&this.editor.forcedHighContrastMode) )
h += '' + l;
else
h += '' + (l ? '' + l + '' : '');
@@ -9234,20 +9782,23 @@ tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
},
selectByIndex : function(idx) {
- var t = this, e, o;
+ var t = this, e, o, label;
if (idx != t.selectedIndex) {
e = DOM.get(t.id + '_text');
+ label = DOM.get(t.id + '_voiceDesc');
o = t.items[idx];
if (o) {
t.selectedValue = o.value;
t.selectedIndex = idx;
DOM.setHTML(e, DOM.encode(o.title));
+ DOM.setHTML(label, t.settings.title + " - " + o.title);
DOM.removeClass(e, 'mceTitle');
DOM.setAttrib(t.id, 'aria-valuenow', o.title);
} else {
DOM.setHTML(e, DOM.encode(t.settings.title));
+ DOM.setHTML(label, DOM.encode(t.settings.title));
DOM.addClass(e, 'mceTitle');
t.selectedValue = t.selectedIndex = null;
DOM.setAttrib(t.id, 'aria-valuenow', t.settings.title);
@@ -9276,7 +9827,7 @@ tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
renderHTML : function() {
var h = '', t = this, s = t.settings, cp = t.classPrefix;
- h = '