<coreobject>
<objectname><![CDATA[wcf\system\ad\AdHandler]]></objectname>
</coreobject>
+
+ <coreobject>
+ <objectname><![CDATA[wcf\data\smiley\SmileyCache]]></objectname>
+ </coreobject>
</import>
</data>
<ul class="smileyList">
{foreach from=$smilies item=smiley}
- <li><a title="{lang}{$smiley->smileyTitle}{/lang}" class="jsTooltip jsSmiley" data-smiley-code="{$smiley->smileyCode}" data-smiley-path="{$smiley->smileyPath}"><img src="{$smiley->getURL()}" alt="{$smiley->smileyCode}" /></a></li>
+ <li><a title="{lang}{$smiley->smileyTitle}{/lang}" class="jsTooltip jsSmiley" data-smiley-code="{$smiley->smileyCode}" data-smiley-path="{$smiley->getURL()}"><img src="{$smiley->getURL()}" alt="{$smiley->smileyCode}" /></a></li>
{/foreach}
</ul>
\ No newline at end of file
-<div id="attachments" class="jsOnly formAttachmentContent tabMenuContent container containerPadding">
+<div class="jsOnly formAttachmentContent container containerPadding" id="attachments_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}">
<ul class="formAttachmentList clearfix"{if !$attachmentHandler->getAttachmentList()|count} style="display: none"{/if}>
{foreach from=$attachmentHandler->getAttachmentList() item=$attachment}
<li class="box48" data-object-id="{@$attachment->attachmentID}">
'wcf.attachment.delete.sure': '{lang}wcf.attachment.delete.sure{/lang}'
});
- new WCF.Attachment.Upload($('#attachments > dl > dd > div'), $('#attachments > ul'), '{@$attachmentObjectType}', '{@$attachmentObjectID}', '{$tmpHash|encodeJS}', '{@$attachmentParentObjectID}', {@$attachmentHandler->getMaxCount()}, '{@$wysiwygContainerID}');
+ new WCF.Attachment.Upload($('#attachments_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if} > dl > dd > div'), $('#attachments_{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if} > ul'), '{@$attachmentObjectType}', '{@$attachmentObjectID}', '{$tmpHash|encodeJS}', '{@$attachmentParentObjectID}', {@$attachmentHandler->getMaxCount()}, '{@$wysiwygContainerID}');
new WCF.Action.Delete('wcf\\data\\attachment\\AttachmentAction', '.formAttachmentList > li');
});
//]]>
{foreach from=$smileyCategories item=smileyCategory}
{assign var=__tabCount value=$__tabCount + 1}
{assign var='__smileyAnchor' value='smilies-'|concat:$smileyCategory->categoryID}
- <li><a href="{$__wcf->getAnchor($__smileyAnchor)}" data-smiley-category-id="{@$smileyCategory->categoryID}">{$smileyCategory->title|language}</a></li>
+ <li data-name="smilies-{@$smileyCategory->categoryID}" data-smiley-category-id="{@$smileyCategory->categoryID}"><a>{$smileyCategory->title|language}</a></li>
{/foreach}
{/capture}
-<div id="smilies" class="jsOnly smiliesContent tabMenuContent container containerPadding{if $__tabCount} tabMenuContainer{/if}">
+<div class="container containerPadding{if $__tabCount} messageTabMenu{/if}" data-preselect="true" data-collapsible="false" id="smilies-{if $wysiwygSelector|isset}{$wysiwygSelector}{else}text{/if}">
{capture assign=__defaultSmilies}
{include file='__messageFormSmilies' smilies=$defaultSmilies}
{/capture}
{if $__tabCount > 1}
- <nav class="menu">
+ <nav class="jsOnly">
<ul>
{@$__categoryTabs}
</ul>
{foreach from=$smileyCategories item=smileyCategory}
{if !$smileyCategory->isDisabled}
- <div id="smilies-{@$smileyCategory->categoryID}" class="hidden">
+ <div id="smilies-{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}-{@$smileyCategory->categoryID}">
{if !$smileyCategory->categoryID}{@$__defaultSmilies}{/if}
</div>
{/if}
<script data-relocate="true">
//<![CDATA[
$(function() {
- new WCF.Message.SmileyCategories();
+ new WCF.Message.SmileyCategories('{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}');
});
//]]>
</script>
-<div class="tabMenuContainer" data-active="{$activeTabMenuItem}" data-store="activeTabMenuItem">
- <nav class="tabMenu jsOnly">
+<div class="messageTabMenu">
+ <nav class="messageTabMenuNavigation jsOnly">
<ul>
- {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies) && $smileyCategories|count}<li id="smiliesTab"><a href="{@$__wcf->getAnchor('smilies')}" title="{lang}wcf.message.smilies{/lang}">{lang}wcf.message.smilies{/lang}</a></li>{/if}
- {if MODULE_ATTACHMENT && $attachmentHandler !== null && $attachmentHandler->canUpload()}<li id="attachmentsTab"><a href="{@$__wcf->getAnchor('attachments')}" title="{lang}wcf.attachment.attachments{/lang}">{lang}wcf.attachment.attachments{/lang}</a></li>{/if}
- <li><a href="{@$__wcf->getAnchor('settings')}" title="{lang}wcf.message.settings{/lang}">{lang}wcf.message.settings{/lang}</a></li>
- {if $__showPoll|isset && $__showPoll}<li><a href="{@$__wcf->getAnchor('poll')}" title="{lang}wcf.poll.management{/lang}">{lang}wcf.poll.management{/lang}</a></li>{/if}
+ {if MODULE_SMILEY && $__wcf->getSession()->getPermission($permissionCanUseSmilies) && $smileyCategories|count}<li data-name="smilies"><a>{lang}wcf.message.smilies{/lang}</a></li>{/if}
+ {if MODULE_ATTACHMENT && $attachmentHandler !== null && $attachmentHandler->canUpload()}<li data-name="attachments"><a>{lang}wcf.attachment.attachments{/lang}</a></li>{/if}
+ <li data-name="settings"><a>{lang}wcf.message.settings{/lang}</a></li>
+ {if $__showPoll|isset && $__showPoll}<li data-name="poll"><a>{lang}wcf.poll.management{/lang}</a></li>{/if}
{event name='tabMenuTabs'}
</ul>
</nav>
//<![CDATA[
$(function() {
if (!$.browser.redactor) $('#smiliesTab, #smilies').remove();
+
+ $('.redactorMessageOptions > nav > ul > li > a').removeAttr('title');
+
+ $('.messageTabMenu').messageTabMenu();
+
+ /*$('.redactorMessageOptions > nav > ul > li > a').click(function() {
+ var $a = $(this);
+ var $p = $a.parent();
+ var $h = $p.hasClass('active');
+
+ $('.redactorMessageOptions > nav > ul > li').removeClass('active');
+ $('.redactorMessageOptions > div, .redactorMessageOptions > fieldset').hide();
+
+ if (!$h) {
+ $p.addClass('active');
+ $('#' + $a.prop('href').replace(/[^#]+#/, '')).show();
+ }
+
+ return false;
+ });
+
+ $('.redactorMessageOptions > nav > ul > li > a:eq(0)').trigger('click');
+
+ $('.redactorMessageOptions > div:eq(0) > nav > ul > li:eq(0)').addClass('active');*/
});
//]]>
</script>
\ No newline at end of file
WCF.System.Dependency.Manager.setup($callbackIdentifier, function() {
var $textarea = $('#' + $editorName);
var $buttons = [ ];
+ var __wysiwygMessageOptions = (typeof $wysiwygMessageOptions === 'undefined') ? [ ] : $wysiwygMessageOptions;
{include file='wysiwygToolbar'}
lang: '{@$__wcf->getLanguage()->getFixedLanguageCode()}',
minHeight: 200,
imageResizable: false,
- plugins: [ 'wutil', 'wmonkeypatch', 'wbutton', 'wbbcode', 'wfontcolor', 'wfontfamily', 'wfontsize' ],
+ plugins: [ 'wutil', 'wmonkeypatch', 'wbutton', 'wbbcode', 'wfontcolor', 'wfontfamily', 'wfontsize', 'woptions' ],
wautosave: {
active: ($autosave) ? true : false,
key: ($autosave) ? '{@$__wcf->getAutosavePrefix()}_' + $autosave : '',
saveOnInit: {if !$errorField|empty}true{else}false{/if}
- }
+ },
+ wMessageOptions: [ ]
};
{if $wysiwygEnableUpload}
$config.plugins.push('wupload');
+ $config.wMessageOptions.push({
+ containerID: 'attachments',
+ title: '{lang}wcf.attachment.attachments{/lang}',
+ items: [ ]
+ });
$config.wattachment = {
attachments: [ ],
maxCount: {@$attachmentHandler->getMaxCount()},
{event name='javascriptInit'}
+ if (__wysiwygMessageOptions.length) {
+ $config.wMessageOptions.push({
+ containerID: 'settings',
+ title: '{lang}wcf.message.settings{/lang}',
+ items: __wysiwygMessageOptions
+ });
+ }
+
+ if (false && $.getLength(__REDACTOR_SMILIES)) {
+ $config.wMessageOptions.push({
+ containerID: 'smilies',
+ title: '{lang}wcf.message.smilies{/lang}',
+ items: [ ]
+ });
+ }
+
$textarea.redactor($config);
});
'{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontsize.js?v={@$__wcfVersion}',
'{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wmonkeypatch.js?v={@$__wcfVersion}',
'{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wutil.js?v={@$__wcfVersion}',
- '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wupload.js?v={@$__wcfVersion}'
+ '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wupload.js?v={@$__wcfVersion}',
+ '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/woptions.js?v={@$__wcfVersion}'
{/if}
{event name='javascriptFiles'}
], function() {
$buttons.push('table');
{/if}
-{if $wysiwygEnableUpload}
- $buttons.push('upload');
-{/if}
-
-{if MODULE_SMILEY && (!$permissionCanUseSmilies|isset || $__wcf->getSession()->getPermission($permissionCanUseSmilies)) && $defaultSmilies|isset && $defaultSmilies|count}
- $buttons.push('smiley');
-{/if}
-
if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
$buttons.push('separator');
}
* Initializes the RedactorPlugins.wbbcode plugin.
*/
init: function() {
- var $dropdown = this._createSmileyDropdown();
+ /*var $dropdown = this._createSmileyDropdown();
this.buttonReplace('smiley', 'wsmiley', 'Smiley', $.proxy(function(btnName, $button, btnObject, e) {
this.dropdownShow(e, btnName);
}, this));
this.buttonGet('wsmiley').data('dropdown', $dropdown);
- this.buttonAwesome('wsmiley', 'fa-smile-o');
+ this.buttonAwesome('wsmiley', 'fa-smile-o');*/
this.opts.initCallback = $.proxy(function() {
if (this.$source.val().length) {
$(document.body).css('overflow', false);
};
+ var $mpDestroy = this.destroy;
+ this.destroy = function() {
+ self.callback('destroy', false, { });
+
+ $mpDestroy.call(self);
+ };
+
// handle indent/outdent
var $mpButtonActiveObserver = this.buttonActiveObserver;
this.buttonActiveObserver = function(e, btnName) {
*/
RedactorPlugins.woptions = {
/**
- * list of message option elements
+ * list of message option elements grouped by instance
* @var object<object>
*/
_messageOptions: { },
/**
- * message option container
- * @var jQuery
+ * message option container per instance
+ * @var object<jQuery>
*/
- _messageOptionContainer: null,
+ _messageOptionContainer: { },
/**
- * navigation container
- * @var jQuery
+ * navigation container per instance
+ * @var object<jQuery>
*/
- _messageOptionNavigation: null,
+ _messageOptionNavigation: { },
/**
* Initializes the RedactorPlugins.woptions plugin.
return;
}
- this._messageOptionContainer = $('<div id="redactorMessageOptions" class="redactorMessageOptions" />').appendTo(this.$box);
- this._messageOptionNavigation = $('<nav><ul /></nav>').appendTo(this._messageOptionContainer).children('ul');
+ var $instanceID = this.$source.wcfIdentify();
+ this.$box.wrap('<div class="redactorContainer" />')
+ this._messageOptionContainer[$instanceID] = $('<div id="redactorMessageOptions" class="redactorMessageOptions" />').insertAfter(this.$box);
+ this._messageOptionNavigation[$instanceID] = $('<nav><ul /></nav>').appendTo(this._messageOptionContainer[$instanceID]).children('ul');
+ this._messageOptions[$instanceID] = { };
for (var $i = 0; $i < $options.length; $i++) {
var $container = $options[$i];
- var $listItem = $('<li><a>' + $container.title + '</a></li>').appendTo(this._messageOptionNavigation);
+ var $listItem = $('<li><a>' + $container.title + '</a></li>').appendTo(this._messageOptionNavigation[$instanceID]);
$listItem.data('containerID', $container.containerID).click($.proxy(this._showMessageOptionContainer, this));
- var $tabContainer = $('<div class="redactorMessageOptionContainer" id="redactorMessageOptions_' + $container.containerID + '" />').hide().appendTo(this._messageOptionContainer);
-
+ var $tabContainer = $('<div class="redactorMessageOptionContainer redactorMessageOptions_' + $container.containerID + '" />').hide().appendTo(this._messageOptionContainer[$instanceID]);
for (var $j = 0; $j < $container.items.length; $j++) {
$($container.items[$j]).appendTo($tabContainer);
}
- this._messageOptions[$container.containerID] = {
+ this._messageOptions[$instanceID][$container.containerID] = {
container: $tabContainer,
listItem: $listItem
};
*/
_showMessageOptionContainer: function(event, containerID) {
var $containerID = (event === null) ? containerID : $(event.currentTarget).data('containerID');
- if (this._messageOptions[$containerID].listItem.hasClass('active')) {
- this._messageOptions[$containerID].listItem.removeClass('active');
- this._messageOptions[$containerID].container.hide();
+ var $instanceID = this.$source.wcfIdentify();
+
+ if (this._messageOptions[$instanceID][$containerID].listItem.hasClass('active')) {
+ this._messageOptions[$instanceID][$containerID].listItem.removeClass('active');
+ this._messageOptions[$instanceID][$containerID].container.hide();
return;
}
- $.each(this._messageOptions, function(containerID, elements) {
+ $.each(this._messageOptions[$instanceID], function(containerID, elements) {
if (containerID == $containerID) {
elements.listItem.addClass('active');
elements.container.show();
* Initializes the attachments user interface.
*/
_initAttachments: function() {
- this._attachmentsContainer = $('#redactorMessageOptions_attachments');
+ this._attachmentsContainer = this._messageOptions[this.$source.wcfIdentify()].attachments.container;
var $attachmentList = $('<ul class="formAttachmentList clearfix" />').hide().appendTo(this._attachmentsContainer);
$('<dl class="wide"><dt></dt><dd><div data-max-size="{@$attachmentHandler->getMaxSize()}"></div><small>' + WCF.String.unescapeHTML(WCF.Language.get('wcf.attachment.upload.limits')) + '</small></dd></dl>').appendTo(this._attachmentsContainer);
*/
_proxy: null,
+ /**
+ * wysiwyg editor selector
+ * @var string
+ */
+ _wysiwygSelector: '',
+
/**
* Initializes the smiley loader.
+ *
+ * @param string wysiwygSelector
*/
- init: function() {
- this._cache = [ ];
+ init: function(wysiwygSelector) {
this._proxy = new WCF.Action.Proxy({
success: $.proxy(this._success, this)
});
+ this._wysiwygSelector = wysiwygSelector;
- $('#smilies').on('wcftabsbeforeactivate', $.proxy(this._click, this));
+ $('#smilies-' + this._wysiwygSelector).on('messagetabmenushow', $.proxy(this._click, this));
// handle onload
- var self = this;
+ /*var self = this;
new WCF.PeriodicalExecuter(function(pe) {
pe.stop();
self._click({ }, { newTab: $('#smilies > .menu li.ui-state-active') });
- }, 100);
+ }, 100);*/
},
/**
* Handles tab menu clicks.
*
* @param object event
- * @param object ui
+ * @param object data
*/
- _click: function(event, ui) {
- var $categoryID = parseInt($(ui.newTab).children('a').data('smileyCategoryID'));
+ _click: function(event, data, c) {
+ var $categoryID = parseInt(data.activeTab.tab.data('smileyCategoryID'));
- if ($categoryID && !WCF.inArray($categoryID, this._cache)) {
- this._proxy.setOption('data', {
- actionName: 'getSmilies',
- className: 'wcf\\data\\smiley\\category\\SmileyCategoryAction',
- objectIDs: [ $categoryID ]
- });
- this._proxy.sendRequest();
+ // ignore global category, will always be pre-loaded
+ if (!$categoryID) {
+ return;
+ }
+
+ // smilies have already been loaded for this tab, ignore
+ if (data.activeTab.container.children('ul.smileyList').length) {
+ return;
}
+
+ // cache exists
+ if (this._cache[$categoryID] !== undefined) {
+ data.activeTab.container.html(this._cache[$categoryID]);
+ }
+
+ // load content
+ this._proxy.setOption('data', {
+ actionName: 'getSmilies',
+ className: 'wcf\\data\\smiley\\category\\SmileyCategoryAction',
+ objectIDs: [ $categoryID ]
+ });
+ this._proxy.sendRequest();
},
/**
*/
_success: function(data, textStatus, jqXHR) {
var $categoryID = parseInt(data.returnValues.smileyCategoryID);
- this._cache.push($categoryID);
+ this._cache[$categoryID] = data.returnValues.template;
- $('#smilies-' + $categoryID).html(data.returnValues.template);
+ $('#smilies-' + this._wysiwygSelector + '-' + $categoryID).html(data.returnValues.template);
}
});
}
}
});
+
+/**
+ * Provides a specialized tab menu used for message options, integrates better into the editor.
+ */
+$.widget('wcf.messageTabMenu', {
+ /**
+ * list of existing tabs and their containers
+ * @var array<object>
+ */
+ _tabs: [ ],
+
+ /**
+ * list of tab names and their corresponding index
+ * @var object<string>
+ */
+ _tabsByName: { },
+
+ /**
+ * widget options
+ * @var object<mixed>
+ */
+ options: {
+ collapsible: true
+ },
+
+ /**
+ * Creates the message tab menu.
+ */
+ _create: function() {
+ var $tabs = this.element.find('> nav > ul > li');
+ var $tabContainers = this.element.find('> div, > fieldset');
+
+ if ($tabs.length != $tabContainers.length) {
+ console.debug("[wcf.messageTabMenu] Amount of tabs does not equal amount of tab containers, aborting.");
+ return;
+ }
+
+ var $preselect = this.element.data('preselect');
+ this._tabs = [ ];
+ this._tabsByName = { };
+ for (var $i = 0; $i < $tabs.length; $i++) {
+ var $tab = $($tabs[$i]);
+ var $tabContainer = $($tabContainers[$i]);
+
+ var $name = $tab.data('name');
+ if ($name === undefined) {
+ var $href = $tab.children('a').prop('href');
+ if ($href !== undefined) {
+ if ($href.match(/#([a-zA-Z_-]+)$/)) {
+ $name = RegExp.$1;
+ }
+ }
+
+ if ($name === undefined) {
+ $name = $tab.wcfIdentify();
+ console.debug("[wcf.messageTabMenu] Missing name attribute, assuming generic ID '" + $name + "'");
+ }
+ }
+
+ this._tabs.push({
+ container: $tabContainer,
+ name: $name,
+ tab: $tab
+ });
+ this._tabsByName[$name] = $i;
+
+ var $anchor = $tab.children('a').data('index', $i).click($.proxy(this._showTab, this));
+ if ($preselect == $name) {
+ $anchor.trigger('click');
+ }
+ }
+
+ if ($preselect === true) {
+ // pick the first available tab
+ this._tabs[0].tab.children('a').trigger('click');
+ }
+
+ var $collapsible = this.element.data('collapsible');
+ if ($collapsible !== undefined) {
+ this.options.collapsible = $collapsible;
+ }
+ },
+
+ /**
+ * Destroys the message tab menu.
+ */
+ destroy: function() {
+ $.Widget.prototype.destroy.apply(this, arguments);
+
+ this.element.remove();
+ },
+
+ /**
+ * Shows a tab or collapses it if already open.
+ *
+ * @param object event
+ * @param integer index
+ * @param boolean forceOpen
+ */
+ _showTab: function(event, index, forceOpen) {
+ var $index = (event === null) ? index : $(event.currentTarget).data('index');
+ forceOpen = (!this.options.collapsible || forceOpen === true) ? true : false;
+
+ var $target = null;
+ for (var $i = 0; $i < this._tabs.length; $i++) {
+ var $current = this._tabs[$i];
+
+ if ($i == $index) {
+ if (!$current.tab.hasClass('active')) {
+ $current.tab.addClass('active');
+ $current.container.addClass('active');
+ $target = $current;
+
+ continue;
+ }
+ else if (forceOpen === true) {
+ continue;
+ }
+ }
+
+ $current.tab.removeClass('active');
+ $current.container.removeClass('active');
+ }
+
+ if (event !== null) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ if ($target !== null) {
+ this._trigger('show', { }, {
+ activeTab: $target
+ });
+ }
+ },
+
+ /**
+ * Toggle a specific tab by either index or name property.
+ *
+ * @param mixed index
+ * @param boolean forceOpen
+ */
+ showTab: function(index, forceOpen) {
+ if (!$.isNumeric(index)) {
+ if (this._tabsByName[index] !== undefined) {
+ index = this._tabsByName[index];
+ }
+ }
+
+ if (this._tabs[index] === undefined) {
+ console.debug("[wcf.messageTabMenu] Cannot locate tab identified by '" + index + "'");
+ return;
+ }
+
+ this._showTab(null, index, forceOpen);
+ },
+
+ /**
+ * Returns a tab by it's unique name.
+ *
+ * @param string name
+ * @return jQuery
+ */
+ getTab: function(name) {
+ if (this._tabsByName[name] !== undefined) {
+ return this._tabs[this._tabsByName[name]].tab;
+ }
+
+ return null;
+ },
+
+ /**
+ * Returns a tab container by it's tab's unique name.
+ *
+ * @param string name
+ * @return jQuery
+ */
+ getContainer: function(name) {
+ if (this._tabsByName[name] !== undefined) {
+ return this._tabs[this._tabsByName[name]].container;
+ }
+
+ return null;
+ }
+});
use wcf\data\smiley\SmileyCache;
use wcf\data\ITraversableObject;
use wcf\system\exception\SystemException;
+use wcf\system\WCF;
/**
* Represents a smiley category.
return null;
}
}
+
+ /**
+ * Returns the category's name.
+ *
+ * @return string
+ */
+ public function __toString() {
+ return WCF::getLanguage()->get($this->title);
+ }
}