Overhauled 'Add Page' UI
authorAlexander Ebert <ebert@woltlab.com>
Mon, 2 May 2016 12:15:25 +0000 (14:15 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Mon, 2 May 2016 12:15:30 +0000 (14:15 +0200)
wcfsetup/install/files/acp/templates/__pageAddContent.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/codemirror.tpl
wcfsetup/install/files/acp/templates/pageAdd.tpl
wcfsetup/install/files/acp/templates/pageAddDialog.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/pageList.tpl
wcfsetup/install/files/acp/templates/wysiwyg.tpl [new file with mode: 0644]
wcfsetup/install/files/acp/templates/wysiwygToolbar.tpl [new file with mode: 0644]
wcfsetup/install/files/js/WoltLab/WCF/Acp/Ui/Page/Add.js [new file with mode: 0644]
wcfsetup/install/files/js/WoltLab/WCF/Ui/Dialog.js
wcfsetup/install/files/lib/acp/form/PageAddForm.class.php
wcfsetup/install/files/lib/acp/page/PageListPage.class.php

diff --git a/wcfsetup/install/files/acp/templates/__pageAddContent.tpl b/wcfsetup/install/files/acp/templates/__pageAddContent.tpl
new file mode 100644 (file)
index 0000000..3c09c19
--- /dev/null
@@ -0,0 +1,14 @@
+<textarea name="content[{@$languageID}]" id="content{@$languageID}">{if !$content[$languageID]|empty}{$content[$languageID]}{/if}</textarea>
+{if $pageType == 'text'}
+       {capture assign='wysiwygSelector'}content{@$languageID}{/capture}
+       
+       {include file='wysiwyg' wysiwygSelector=$wysiwygSelector}
+{elseif $pageType == 'html'}
+       {capture assign='codemirrorSelector'}#content{@$languageID}{/capture}
+       
+       {include file='codemirror' codemirrorMode='htmlmixed' codemirrorSelector=$codemirrorSelector}
+{elseif $pageType == 'tpl'}
+       {capture assign='codemirrorSelector'}#content{@$languageID}{/capture}
+       
+       {include file='codemirror' codemirrorMode='smartymixed' codemirrorSelector=$codemirrorSelector}
+{/if}
\ No newline at end of file
index 7b18d11ee3fced5f8d4ec107ab9daf67174c8387..9edce7d3fd407091d5de7cb27c68129c6c9954f9 100644 (file)
@@ -9,6 +9,18 @@
 {if $codemirrorMode|isset}
        <script data-relocate="true">window.define.amd = undefined;</script>
        <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/{if $codemirrorMode == 'text/x-less'}css/css{else}{$codemirrorMode}/{$codemirrorMode}{/if}.js"></script>
+       
+       {if $codemirrorMode == 'htmlmixed' || $codemirrorMode == 'smartymixed'}
+               {if $codemirrorMode == 'smartymixed'}
+                       <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/htmlmixed/htmlmixed.js"></script>
+                       <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/smarty/smarty.js"></script>
+               {/if}
+               
+               <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/css/css.js"></script>
+               <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/javascript/javascript.js"></script>
+               <script data-relocate="true" src="{@$__wcf->getPath()}js/3rdParty/codemirror/mode/xml/xml.js"></script>
+       {/if}
+       
        <script data-relocate="true">window.define.amd = window.__require_define_amd;</script>
 {/if}
 {event name='javascriptIncludes'}
index bcf74ab7b2d4cbd31423dfe8041dd620ed210a6d..a0cd7f35e2f4f9e9421fe231b480c8b814d813bd 100644 (file)
                        </dd>
                </dl>
                
-               <dl{if $errorField == 'pageType'} class="formError"{/if}>
-                       <dt><label for="pageType">{lang}wcf.acp.page.pageType{/lang}</label></dt>
-                       <dd>
-                               <select name="pageType" id="pageType"{if $action == 'edit'} disabled="disabled"{/if}>
-                                       {foreach from=$availablePageTypes item=availablePageType}
-                                               <option value="{@$availablePageType}"{if $availablePageType == $pageType} selected="selected"{/if}>{lang}wcf.acp.page.pageType.{@$availablePageType}{/lang}</option>
-                                       {/foreach}
-                               </select>
-                               
-                               {if $errorField == 'pageType'}
-                                       <small class="innerError">
-                                               {if $errorType == 'empty'}
-                                                       {lang}wcf.global.form.error.empty{/lang}
-                                               {else}
-                                                       {lang}wcf.acp.page.pageType.error.{@$errorType}{/lang}
-                                               {/if}
-                                       </small>
-                               {/if}
-                       </dd>
-               </dl>
-       
                <dl{if $errorField == 'parentPageID'} class="formError"{/if}>
                        <dt><label for="parentPageID">{lang}wcf.acp.page.parentPageID{/lang}</label></dt>
                        <dd>
                                <dl{if $errorField == 'content'} class="formError"{/if}>
                                        <dt><label for="content0">{lang}wcf.acp.page.content{/lang}</label></dt>
                                        <dd>
-                                               <textarea name="content[0]" id="content0">{if !$content[0]|empty}{$content[0]}{/if}</textarea>
+                                               {include file='__pageAddContent' languageID=0}
+                                               
                                                {if $errorField == 'content'}
                                                        <small class="innerError">
                                                                {if $errorType == 'empty'}
                                                        <dl{if $errorField == 'content'} class="formError"{/if}>
                                                                <dt><label for="content{@$availableLanguage->languageID}">{lang}wcf.acp.page.content{/lang}</label></dt>
                                                                <dd>
-                                                                       <textarea name="content[{@$availableLanguage->languageID}]" id="content{@$availableLanguage->languageID}">{if !$content[$availableLanguage->languageID]|empty}{$content[$availableLanguage->languageID]}{/if}</textarea>
+                                                                       {include file='__pageAddContent' languageID=$availableLanguage->languageID}
+                                                                       
                                                                        {if $errorField == 'content'}
                                                                                <small class="innerError">
                                                                                        {if $errorType == 'empty'}
        <div class="formSubmit">
                <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
                <input type="hidden" name="isMultilingual" value="{@$isMultilingual}">
+               <input type="hidden" name="pageType" value="{$pageType}">
                {@SECURITY_TOKEN_INPUT_TAG}
        </div>
 </form>
diff --git a/wcfsetup/install/files/acp/templates/pageAddDialog.tpl b/wcfsetup/install/files/acp/templates/pageAddDialog.tpl
new file mode 100644 (file)
index 0000000..088687f
--- /dev/null
@@ -0,0 +1,40 @@
+<div id="pageAddDialog" style="display: none">
+       <div class="section">
+               <dl>
+                       <dt>{lang}wcf.acp.page.type{/lang}</dt>
+                       <dd>
+                               <label><input type="radio" name="pageType" value="text" checked> {lang}wcf.acp.page.type.text{/lang}</label>
+                               <small>{lang}wcf.acp.page.type.wysiwyg.description{/lang}</small>
+                               <label><input type="radio" name="pageType" value="html"> {lang}wcf.acp.page.type.html{/lang}</label>
+                               <small>{lang}wcf.acp.page.type.html.description{/lang}</small>
+                               <label><input type="radio" name="pageType" value="tpl"> {lang}wcf.acp.page.type.tpl{/lang}</label>
+                               <small>{lang}wcf.acp.page.type.tpl.description{/lang}</small>
+                       </dd>
+               </dl>
+               
+               <dl>
+                       <dt>{lang}wcf.acp.page.i18n{/lang}</dt>
+                       <dd>
+                               <label><input type="radio" name="isMultilingual" value="0" checked> {lang}wcf.acp.page.i18n.none{/lang}</label>
+                               <small>{lang}wcf.acp.page.i18n.none.description{/lang}</small>
+                               <label><input type="radio" name="isMultilingual" value="1"> {lang}wcf.acp.page.i18n.i18n{/lang}</label>
+                               <small>{lang}wcf.acp.page.i18n.i18n.description{/lang}</small>
+                       </dd>
+               </dl>
+               
+               <div class="formSubmit">
+                       <button class="buttonPrimary">{lang}wcf.global.button.next{/lang}</button>
+               </div>
+       </div>
+</div>
+<script data-relocate="true">
+       require(['WoltLab/WCF/Acp/Ui/Page/Add'], function(AcpUiPageAdd) {
+               AcpUiPageAdd.init('{link controller='PageAdd' encode=false}{literal}pageType={$pageType}&isMultilingual={$isMultilingual}{/literal}{/link}');
+               
+               {if $showPageAddDialog}
+                       window.setTimeout(function() {
+                               AcpUiPageAdd.openDialog();
+                       }, 10);
+               {/if}
+       });
+</script>
index 796423c320f31b589e85c2b00a37e152a8b40802..3f39c05e0d79bbf1d6a0e3f727775040e255c4f9 100644 (file)
@@ -16,9 +16,7 @@
        
        <nav class="contentHeaderNavigation">
                <ul>
-                       <li><a href="{link controller='PageLanding'}{/link}" class="button"><span class="icon icon16 fa-home"></span> {lang}wcf.acp.page.landing{/lang}</a></li>
-                       <li><a href="{link controller='PageAdd'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
-                       <li><a href="{link controller='PageAdd'}isMultilingual=1{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.addMultilingual{/lang}</span></a></li>
+                       <li><a href="#" class="button jsButtonPageAdd"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
                        
                        {event name='contentHeaderNavigation'}
                </ul>
                
                <nav class="contentFooterNavigation">
                        <ul>
-                               <li><a href="{link controller='PageLanding'}{/link}" class="button"><span class="icon icon16 fa-home"></span> {lang}wcf.acp.page.landing{/lang}</a></li>
-                               <li><a href="{link controller='PageAdd'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
-                               <li><a href="{link controller='PageAdd'}isMultilingual=1{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.addMultilingual{/lang}</span></a></li>
+                               <li><a href="#" class="button jsButtonPageAdd"><span class="icon icon16 fa-plus"></span> <span>{lang}wcf.acp.page.add{/lang}</span></a></li>
                                
                                {event name='contentFooterNavigation'}
                        </ul>
        </footer>
 {/if}
 
+{include file='pageAddDialog'}
+
 {include file='footer'}
diff --git a/wcfsetup/install/files/acp/templates/wysiwyg.tpl b/wcfsetup/install/files/acp/templates/wysiwyg.tpl
new file mode 100644 (file)
index 0000000..5991bba
--- /dev/null
@@ -0,0 +1,221 @@
+<style>
+       woltlab-mention {
+               background-color: rgb(240, 248, 255);
+               border: 1px solid rgb(52, 152, 219);
+               display: inline-block;
+               margin: 0 3px;
+               padding: 0 2px;
+       }
+</style>
+<script data-relocate="true">
+(function() {
+       var buttons = ['format', 'wcfSeparator', 'bold', 'italic', 'underline', 'deleted', 'wcfSeparator', 'lists', 'image', 'link'];
+       
+       var elementId = '{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}';
+       var callbackIdentifier = 'Redactor2_' + elementId;
+       
+       WCF.System.Dependency.Manager.setup(callbackIdentifier, function() {
+               // TODO: Should the media stuff be here?
+               {include file='mediaJavaScript'}
+               
+               var element = elById(elementId);
+               var autosave = elData(element, 'autosave') || '';
+               if (autosave) {
+                       element.removeAttribute('data-autosave');
+               }
+               
+               var config = {
+                       buttons: buttons,
+                       minHeight: 200,
+                       plugins: ['WoltLabButton', 'WoltLabColor', 'WoltLabDropdown', 'WoltLabEvent', 'WoltLabLink', 'WoltLabQuote'],
+                       toolbarFixed: false,
+                       woltlab: {
+                               autosave: autosave
+                       }
+               };
+               
+               // user mentions
+               if (elDataBool(element, 'support-mention')) {
+                       config.plugins.push('WoltLabMention');
+               }
+               
+               // media
+               {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}
+                       config.plugins.push('WoltLabMedia');
+               {/if}
+               
+               $(element).redactor(config);
+       });
+               
+       head.load([
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/redactor.js?v={@LAST_UPDATE_TIME}',
+               
+               {* WoltLab *}
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabButton.js?v={@LAST_UPDATE_TIME}',
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabColor.js?v={@LAST_UPDATE_TIME}',
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabDropdown.js?v={@LAST_UPDATE_TIME}', 
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabEvent.js?v={@LAST_UPDATE_TIME}',
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabLink.js?v={@LAST_UPDATE_TIME}',
+               {if $__wcf->session->getPermission('admin.content.cms.canUseMedia')}'{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMedia.js?v={@LAST_UPDATE_TIME}',{/if}
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabMention.js?v={@LAST_UPDATE_TIME}',
+               '{@$__wcf->getPath()}js/3rdParty/redactor2/plugins/WoltLabQuote.js?v={@LAST_UPDATE_TIME}'
+               
+               ], function() {
+                       WCF.System.Dependency.Manager.invoke(callbackIdentifier);
+               }
+       );
+})();
+</script>
+
+{*
+<script data-relocate="true">
+var __REDACTOR_ICON_PATH = '{@$__wcf->getPath()}icon/';
+var __REDACTOR_BUTTONS = [ {implode from=$__wcf->getBBCodeHandler()->getButtonBBCodes() item=__bbcode}{ icon: '{$__bbcode->wysiwygIcon}', label: '{$__bbcode->buttonLabel|language}', name: '{$__bbcode->bbcodeTag}' }{/implode} ];
+var __REDACTOR_SMILIES = { {implode from=$__wcf->getSmileyCache()->getCategorySmilies() item=smiley}'{@$smiley->smileyCode|encodeJS}': '{@$smiley->getURL()|encodeJS}'{/implode} };
+var __REDACTOR_BBCODES = [ {implode from=$__wcf->getBBCodeHandler()->getBBCodes() item=__bbcode}'{@$__bbcode->bbcodeTag}'{/implode} ];
+var __REDACTOR_SOURCE_BBCODES = [ {implode from=$__wcf->getBBCodeHandler()->getSourceBBCodes() item=__bbcode}'{@$__bbcode->bbcodeTag}'{/implode} ];
+var __REDACTOR_CODE_HIGHLIGHTERS = { {implode from=$__wcf->getBBCodeHandler()->getHighlighters() item=__highlighter}'{@$__highlighter}': '{lang}wcf.bbcode.code.{@$__highlighter}.title{/lang}'{/implode} };
+var __REDACTOR_AMD_DEPENDENCIES = { };
+
+require(['Language', 'WoltLab/WCF/Bbcode/FromHtml', 'WoltLab/WCF/Bbcode/ToHtml'], function(Language, BbcodeFromHTML, BbcodeToHTML) {
+__REDACTOR_AMD_DEPENDENCIES = {
+BbcodeFromHTML: BbcodeFromHTML,
+BbcodeToHTML: BbcodeToHTML
+};
+
+Language.addObject({
+'wcf.attachment.dragAndDrop.dropHere': '{lang}wcf.attachment.dragAndDrop.dropHere{/lang}',
+'wcf.attachment.dragAndDrop.dropNow': '{lang}wcf.attachment.dragAndDrop.dropNow{/lang}',
+'wcf.bbcode.button.fontColor': '{lang}wcf.bbcode.button.fontColor{/lang}',
+'wcf.bbcode.button.fontFamily': '{lang}wcf.bbcode.button.fontFamily{/lang}',
+'wcf.bbcode.button.fontSize': '{lang}wcf.bbcode.button.fontSize{/lang}',
+'wcf.bbcode.button.image': '{lang}wcf.bbcode.button.image{/lang}',
+'wcf.bbcode.button.redo': '{lang}wcf.bbcode.button.redo{/lang}',
+'wcf.bbcode.button.subscript': '{lang}wcf.bbcode.button.subscript{/lang}',
+'wcf.bbcode.button.superscript': '{lang}wcf.bbcode.button.superscript{/lang}',
+'wcf.bbcode.button.toggleBBCode': '{lang}wcf.bbcode.button.toggleBBCode{/lang}',
+'wcf.bbcode.button.toggleHTML': '{lang}wcf.bbcode.button.toggleHTML{/lang}',
+'wcf.bbcode.button.undo': '{lang}wcf.bbcode.button.undo{/lang}',
+'wcf.bbcode.code': '{lang}wcf.bbcode.code{/lang}',
+'wcf.bbcode.code.edit': '{lang}wcf.bbcode.code.edit{/lang}',
+'wcf.bbcode.code.filename': '{lang}wcf.bbcode.code.filename{/lang}',
+'wcf.bbcode.code.filename.description': '{lang}wcf.bbcode.code.filename.description{/lang}',
+'wcf.bbcode.code.highlighter': '{lang}wcf.bbcode.code.highlighter{/lang}',
+'wcf.bbcode.code.highlighter.description': '{lang}wcf.bbcode.code.highlighter.description{/lang}',
+'wcf.bbcode.code.highlighter.none': '{lang}wcf.bbcode.code.highlighter.none{/lang}',
+'wcf.bbcode.code.insert': '{lang}wcf.bbcode.code.insert{/lang}',
+'wcf.bbcode.code.lineNumber': '{lang}wcf.bbcode.code.lineNumber{/lang}',
+'wcf.bbcode.code.lineNumber.description': '{lang}wcf.bbcode.code.lineNumber.description{/lang}',
+'wcf.bbcode.code.settings': '{lang}wcf.bbcode.code.settings{/lang}',
+'wcf.bbcode.image.source': '{lang}wcf.bbcode.image.source{/lang}',
+'wcf.bbcode.quote.edit': '{lang}wcf.bbcode.quote.edit{/lang}',
+'wcf.bbcode.quote.edit.author': '{lang}wcf.bbcode.quote.edit.author{/lang}',
+'wcf.bbcode.quote.edit.link': '{lang}wcf.bbcode.quote.edit.link{/lang}',
+'wcf.bbcode.quote.insert': '{lang}wcf.bbcode.quote.insert{/lang}',
+'wcf.bbcode.quote.title.clickToSet': '{lang}wcf.bbcode.quote.title.clickToSet{/lang}',
+'wcf.bbcode.quote.title.javascript': '{lang}wcf.bbcode.quote.title.javascript{/lang}',
+'wcf.global.noSelection': '{lang}wcf.global.noSelection{/lang}',
+'wcf.message.autosave.prompt': '{lang}wcf.message.autosave.prompt{/lang}',
+'wcf.message.autosave.prompt.confirm': '{lang}wcf.message.autosave.prompt.confirm{/lang}',
+'wcf.message.autosave.prompt.discard': '{lang}wcf.message.autosave.prompt.discard{/lang}',
+'wcf.message.autosave.restored': '{lang}wcf.message.autosave.restored{/lang}',
+'wcf.message.autosave.restored.confirm': '{lang}wcf.message.autosave.restored.confirm{/lang}',
+'wcf.message.autosave.restored.revert': '{lang}wcf.message.autosave.restored.revert{/lang}',
+'wcf.message.autosave.restored.revert.confirmMessage': '{lang}wcf.message.autosave.restored.revert.confirmMessage{/lang}',
+'wcf.message.autosave.restored.version': '{lang __literal=true}wcf.message.autosave.restored.version{/lang}',
+'wcf.message.autosave.saved': '{lang}wcf.message.autosave.saved{/lang}'
+});
+
+var $editorName = '{if $wysiwygSelector|isset}{$wysiwygSelector|encodeJS}{else}text{/if}';
+var $callbackIdentifier = 'Redactor_' + $editorName;
+
+WCF.System.Dependency.Manager.setup($callbackIdentifier, function() {
+var $textarea = $('#' + $editorName);
+var $buttons = [ ];
+
+{include file='wysiwygToolbar'}
+
+var $autosave = $textarea.data('autosave');
+var $autosaveLastEditTime = ($autosave && $textarea.data('autosaveLastEditTime')) ? (parseInt($textarea.data('autosaveLastEditTime')) || 0) : 0;
+var $autosavePrompt = ($autosave && $textarea.data('autosavePrompt')) ? true : false;
+var $config = {
+       autosave: false,
+       buttons: $buttons,
+       convertImageLinks: false,
+       convertUrlLinks: false,
+       convertVideoLinks: false,
+       direction: '{lang}wcf.global.pageDirection{/lang}',
+       lang: '{@$__wcf->getLanguage()->getFixedLanguageCode()}',
+       linebreaks: true,
+       maxHeight: 500,
+       minHeight: 200,
+       plugins: [ 'wutil', 'wautosave', 'wmonkeypatch', 'wbutton', 'wbbcode', 'wfontcolor', 'wfontfamily', 'wfontsize' ],
+       removeEmpty: false,
+       replaceDivs: false,
+       source: true,
+       tabifier: false,
+       toolbarFixed: false,
+       woltlab: {
+               autosave: {
+                       active: ($autosave) ? true : false,
+                       key: ($autosave) ? '{@$__wcf->getAutosavePrefix()}_' + $autosave : '',
+                       lastEditTime: $autosaveLastEditTime,
+                       prefix: '{@$__wcf->getAutosavePrefix()}',
+                       prompt: $autosavePrompt,
+                       saveOnInit: {if !$errorField|empty}true{else}false{/if}
+               },
+               originalValue: $textarea.val()
+       }
+};
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('table')}
+       $config.plugins.splice(2, 0, 'table');
+{/if}
+
+// TODO: is this still required?
+if ($.browser.iOS) {
+       // using a zero-width space breaks iOS' detection of the start of a sentence, causing the first word to be lowercased
+       $config.emptyHtml = '<p><br></p>';
+}
+
+{if MODULE_ATTACHMENT && !$attachmentHandler|empty && $attachmentHandler->canUpload()}
+       $config.plugins.push('wupload');
+       $config.woltlab.attachmentUrl = '{link controller='Attachment' id=987654321}{/link}';
+       $config.woltlab.attachmentThumbnailUrl = '{link controller='Attachment' id=987654321}thumbnail=1{/link}';
+{/if}
+
+{event name='javascriptInit'}
+
+// clear textarea before init
+$textarea.val('');
+
+$textarea.redactor($config);
+});
+
+head.load([
+'{@$__wcf->getPath()}js/3rdParty/redactor/redactor{if !ENABLE_DEBUG_MODE}.min{/if}.js?v={@LAST_UPDATE_TIME}',
+{if $__wcf->getLanguage()->getFixedLanguageCode() != 'en'}'{@$__wcf->getPath()}js/3rdParty/redactor/languages/{@$__wcf->getLanguage()->getFixedLanguageCode()}.js?v={@LAST_UPDATE_TIME}',{/if}
+{if !ENABLE_DEBUG_MODE}
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wcombined.min.js?v={@LAST_UPDATE_TIME}'
+{else}
+       {* official *}{*
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/table.js?v={@LAST_UPDATE_TIME}',
+       
+       {* WoltLab *}{*
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wautosave.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbbcode.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wbutton.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontcolor.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontfamily.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wfontsize.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wmonkeypatch.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wutil.js?v={@LAST_UPDATE_TIME}',
+       '{@$__wcf->getPath()}js/3rdParty/redactor/plugins/wupload.js?v={@LAST_UPDATE_TIME}'
+{/if}
+{event name='javascriptFiles'}
+], function() {
+WCF.System.Dependency.Manager.invoke($callbackIdentifier);
+});
+});
+</script>
+*}
diff --git a/wcfsetup/install/files/acp/templates/wysiwygToolbar.tpl b/wcfsetup/install/files/acp/templates/wysiwygToolbar.tpl
new file mode 100644 (file)
index 0000000..6c2f63e
--- /dev/null
@@ -0,0 +1,73 @@
+$buttons.push('html');
+
+$buttons.push('separator');
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('b')}
+       $buttons.push('bold');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('i')}
+       $buttons.push('italic');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('u')}
+       $buttons.push('underline');
+{/if}
+
+if ($buttons.length) {
+       $buttons.push('separator');
+}
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('s')}
+       $buttons.push('deleted');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('sub')}
+       $buttons.push('subscript');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('sup')}
+       $buttons.push('superscript');
+{/if}
+
+if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
+       $buttons.push('separator');
+}
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('list')}
+       $buttons.push('orderedlist');
+       $buttons.push('unorderedlist');
+       $buttons.push('outdent');
+       $buttons.push('indent');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('align')}
+       $buttons.push('alignment');
+{/if}
+
+if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
+       $buttons.push('separator');
+}
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('font')}
+       $buttons.push('fontfamily');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('size')}
+       $buttons.push('fontsize');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('color')}
+       $buttons.push('fontcolor');
+{/if}
+
+if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
+       $buttons.push('separator');
+}
+
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('url')}
+       $buttons.push('link');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('img')}
+       $buttons.push('image');
+{/if}
+{if $__wcf->getBBCodeHandler()->isAvailableBBCode('table')}
+       $buttons.push('table');
+{/if}
+
+if ($buttons.length && $buttons[$buttons.length -1] != 'separator') {
+       $buttons.push('separator');
+}
diff --git a/wcfsetup/install/files/js/WoltLab/WCF/Acp/Ui/Page/Add.js b/wcfsetup/install/files/js/WoltLab/WCF/Acp/Ui/Page/Add.js
new file mode 100644 (file)
index 0000000..87b0713
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * Provides the dialog overlay to add a new page.
+ * 
+ * @author     Alexander Ebert
+ * @copyright  2001-2016 WoltLab GmbH
+ * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module     WoltLab/WCF/Acp/Ui/Page/Add
+ */
+define(['Core', 'Language', 'Ui/Dialog'], function(Core, Language, UiDialog) {
+       "use strict";
+       
+       var _link;
+       
+       /**
+        * @exports     WoltLab/WCF/Acp/Ui/Page/Add
+        */
+       return {
+               /**
+                * Initializes the page add handler.
+                * 
+                * @param       {string}        link    redirect URL
+                */
+               init: function(link) {
+                       _link = link;
+                       
+                       var buttons = elBySelAll('.jsButtonPageAdd');
+                       for (var i = 0, length = buttons.length; i < length; i++) {
+                               buttons[i].addEventListener(WCF_CLICK_EVENT, this.openDialog.bind(this));
+                       }
+               },
+               
+               /**
+                * Opens the 'Add Page' dialog.
+                * 
+                * @param       {Event=}        event   event object
+                */
+               openDialog: function(event) {
+                       if (event instanceof Event) {
+                               event.preventDefault();
+                       }
+                       
+                       UiDialog.open(this);
+               },
+               
+               _dialogSetup: function() {
+                       return {
+                               id: 'pageAddDialog',
+                               options: {
+                                       onSetup: function(content) {
+                                               elBySel('button', content).addEventListener(WCF_CLICK_EVENT, function(event) {
+                                                       event.preventDefault();
+                                                       
+                                                       var pageType = elBySel('input[name="pageType"]:checked', content).value;
+                                                       var isMultilingual = elBySel('input[name="isMultilingual"]:checked', content).value;
+                                                       
+                                                       window.location = _link.replace(/{\$pageType}/, pageType).replace(/{\$isMultilingual}/, isMultilingual);
+                                               });
+                                       },
+                                       title: Language.get('wcf.acp.page.add')
+                               }
+                       };
+               }
+       }
+});
index 141eacaac47dd76381d36664c116e1bd18d2c1a4..207057dcc3ef1aaa81c74f285a2a11baaa33abfe 100644 (file)
@@ -121,6 +121,10 @@ define(
                                
                                setupData.source = document.createDocumentFragment();
                                setupData.source.appendChild(dialogElement);
+                               
+                               // remove id and `display: none` from dialog element
+                               dialogElement.removeAttribute('id');
+                               elShow(dialogElement);
                        }
                        else if (setupData.source === null) {
                                // `null` means there is no static markup and `html` should be used instead
index 28a195450077d3bdd1b98c61bb68ae114485699f..e405afd1178c67d3aec2477296ea3b54d9ffc349 100644 (file)
@@ -9,11 +9,15 @@ use wcf\data\page\PageAction;
 use wcf\data\page\PageEditor;
 use wcf\data\page\PageNodeTree;
 use wcf\form\AbstractForm;
+use wcf\system\exception\IllegalLinkException;
 use wcf\system\exception\UserInputException;
+use wcf\system\html\input\HtmlInputProcessor;
 use wcf\system\language\LanguageFactory;
+use wcf\system\request\LinkHandler;
 use wcf\system\request\RouteHandler;
 use wcf\system\WCF;
 use wcf\util\ArrayUtil;
+use wcf\util\HeaderUtil;
 use wcf\util\StringUtil;
 
 /**
@@ -139,8 +143,24 @@ class PageAddForm extends AbstractForm {
         */
        public function readParameters() {
                parent::readParameters();
-       
+               
+               // work-around to force adding pages via dialog overlay
+               if (empty($_POST) && !isset($_GET['pageType'])) {
+                       HeaderUtil::redirect(LinkHandler::getInstance()->getLink('PageList', ['showPageAddDialog' => 1]));
+                       exit;
+               }
+               
                if (!empty($_REQUEST['isMultilingual'])) $this->isMultilingual = 1;
+               if (!empty($_REQUEST['pageType'])) $this->pageType = $_REQUEST['pageType'];
+               
+               if ($this->action == 'add') {
+                       try {
+                               $this->validatePageType();
+                       }
+                       catch (UserInputException $e) {
+                               throw new IllegalLinkException();
+                       }
+               }
                
                // get available applications
                $applicationList = new ApplicationList();
@@ -161,7 +181,6 @@ class PageAddForm extends AbstractForm {
                parent::readFormParameters();
                
                if (isset($_POST['parentPageID'])) $this->parentPageID = intval($_POST['parentPageID']);
-               if (isset($_POST['pageType'])) $this->pageType = $_POST['pageType'];
                if (isset($_POST['name'])) $this->name = StringUtil::trim($_POST['name']);
                if (isset($_POST['isDisabled'])) $this->isDisabled = 1;
                if (isset($_POST['isLandingPage'])) $this->isLandingPage = 1;
@@ -213,9 +232,13 @@ class PageAddForm extends AbstractForm {
         * Validates page type.
         */
        protected function validatePageType() {
-               if (!in_array($this->pageType, Page::$availablePageTypes) || ($this->isMultilingual && $this->pageType == 'system')) {
+               if (!in_array($this->pageType, Page::$availablePageTypes) || ($this->action == 'add' && $this->pageType == 'system')) {
                        throw new UserInputException('pageType');
                }
+               
+               if ($this->pageType == 'system') {
+                       $this->isMultilingual = 0;
+               }
        }
        
        /**
@@ -311,6 +334,15 @@ class PageAddForm extends AbstractForm {
        public function save() {
                parent::save();
                
+               $parseHTML = function($content) {
+                       if ($this->pageType == 'text') {
+                               $htmlInputProcessor = new HtmlInputProcessor();
+                               $content = $htmlInputProcessor->process($content);
+                       }
+                       
+                       return $content;
+               };
+               
                // prepare page content
                $content = [];
                if ($this->isMultilingual) {
@@ -318,7 +350,7 @@ class PageAddForm extends AbstractForm {
                                $content[$language->languageID] = [
                                        'customURL' => (!empty($_POST['customURL'][$language->languageID]) ? $_POST['customURL'][$language->languageID] : ''),
                                        'title' => (!empty($_POST['title'][$language->languageID]) ? $_POST['title'][$language->languageID] : ''),
-                                       'content' => (!empty($_POST['content'][$language->languageID]) ? $_POST['content'][$language->languageID] : ''),
+                                       'content' => (!empty($_POST['content'][$language->languageID]) ? $parseHTML($_POST['content'][$language->languageID]) : ''),
                                        'metaDescription' => (!empty($_POST['metaDescription'][$language->languageID]) ? $_POST['metaDescription'][$language->languageID] : ''),
                                        'metaKeywords' => (!empty($_POST['metaKeywords'][$language->languageID]) ? $_POST['metaKeywords'][$language->languageID] : '')
                                ];
@@ -328,7 +360,7 @@ class PageAddForm extends AbstractForm {
                        $content[0] = [
                                'customURL' => (!empty($_POST['customURL'][0]) ? $_POST['customURL'][0] : ''),
                                'title' => (!empty($_POST['title'][0]) ? $_POST['title'][0] : ''),
-                               'content' => (!empty($_POST['content'][0]) ? $_POST['content'][0] : ''),
+                               'content' => (!empty($_POST['content'][0]) ? $parseHTML($_POST['content'][0]) : ''),
                                'metaDescription' => (!empty($_POST['metaDescription'][0]) ? $_POST['metaDescription'][0] : ''),
                                'metaKeywords' => (!empty($_POST['metaKeywords'][0]) ? $_POST['metaKeywords'][0] : '')
                        ];
@@ -364,15 +396,9 @@ class PageAddForm extends AbstractForm {
                // call saved event
                $this->saved();
                
-               // show success
-               WCF::getTPL()->assign('success', true);
-               
-               // reset variables
-               $this->parentPageID = $this->isDisabled = $this->isLandingPage = 0;
-               $this->applicationPackageID = 1;
-               $this->name = $this->controller = '';
-               $this->pageType = 'text';
-               $this->customURL = $this->title = $this->content = $this->metaDescription = $this->metaKeywords = [];
+               // forward to page list
+               HeaderUtil::redirect(LinkHandler::getInstance()->getLink('PageList'));
+               exit;
        }
        
        /**
@@ -395,8 +421,6 @@ class PageAddForm extends AbstractForm {
        public function assignVariables() {
                parent::assignVariables();
                
-               $availablePageTypes = Page::$availablePageTypes;
-               if ($this->isMultilingual) unset($availablePageTypes[array_search('system', $availablePageTypes)]);
                WCF::getTPL()->assign([
                        'action' => 'add',
                        'parentPageID' => $this->parentPageID,
@@ -415,7 +439,6 @@ class PageAddForm extends AbstractForm {
                        'boxIDs' => $this->boxIDs,
                        'availableApplications' => $this->availableApplications,
                        'availableLanguages' => LanguageFactory::getInstance()->getLanguages(),
-                       'availablePageTypes' => $availablePageTypes,
                        'availableBoxes' => $this->availableBoxes,
                        'pageNodeList' => (new PageNodeTree())->getNodeList()
                ]);
index f782a616cea1e0608dda1de39f6844675bf04aff..c0e16b7d2c7ef886bc8a7b3613fc506d25e6d1b1 100644 (file)
@@ -1,5 +1,6 @@
 <?php
 namespace wcf\acp\page;
+use wcf\data\application\Application;
 use wcf\data\application\ApplicationList;
 use wcf\page\SortablePage;
 use wcf\system\WCF;
@@ -9,7 +10,7 @@ use wcf\util\StringUtil;
  * Shows a list of pages.
  * 
  * @author     Marcel Werk
- * @copyright  2001-2015 WoltLab GmbH
+ * @copyright  2001-2016 WoltLab GmbH
  * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
  * @package    com.woltlab.wcf
  * @subpackage acp.page
@@ -30,7 +31,7 @@ class PageListPage extends SortablePage {
        /**
         * @inheritdoc
         */
-       public $neededPermissions = array('admin.content.cms.canManagePage');
+       public $neededPermissions = ['admin.content.cms.canManagePage'];
        
        /**
         * @inheritdoc
@@ -40,7 +41,7 @@ class PageListPage extends SortablePage {
        /**
         * @inheritdoc
         */
-       public $validSortFields = array('pageID', 'name', 'lastUpdateTime');
+       public $validSortFields = ['pageID', 'name', 'lastUpdateTime'];
        
        /**
         * name
@@ -74,10 +75,16 @@ class PageListPage extends SortablePage {
        
        /**
         * list of available applications
-        * @var \wcf\data\application\Application[]
+        * @var Application[]
         */
        public $availableApplications = [];
        
+       /**
+        * display 'Add Page' dialog on load
+        * @var integer
+        */
+       public $showPageAddDialog = 0;
+       
        /**
         * @inheritdoc
         */
@@ -89,6 +96,7 @@ class PageListPage extends SortablePage {
                if (!empty($_REQUEST['content'])) $this->content = StringUtil::trim($_REQUEST['content']);
                if (isset($_REQUEST['applicationPackageID'])) $this->applicationPackageID = intval($_REQUEST['applicationPackageID']);
                if (!empty($_REQUEST['pageType'])) $this->pageType = $_REQUEST['pageType'];
+               if (!empty($_REQUEST['showPageAddDialog'])) $this->showPageAddDialog = 1;
                
                // get available applications
                $applicationList = new ApplicationList();
@@ -103,22 +111,22 @@ class PageListPage extends SortablePage {
                parent::initObjectList();
                
                if (!empty($this->name)) {
-                       $this->objectList->getConditionBuilder()->add('page.name LIKE ?', array('%'.$this->name.'%'));
+                       $this->objectList->getConditionBuilder()->add('page.name LIKE ?', ['%'.$this->name.'%']);
                }
                if (!empty($this->title)) {
-                       $this->objectList->getConditionBuilder()->add('page.pageID IN (SELECT pageID FROM wcf'.WCF_N.'_page_content WHERE title LIKE ?)', array('%'.$this->title.'%'));
+                       $this->objectList->getConditionBuilder()->add('page.pageID IN (SELECT pageID FROM wcf'.WCF_N.'_page_content WHERE title LIKE ?)', ['%'.$this->title.'%']);
                }
                if (!empty($this->content)) {
-                       $this->objectList->getConditionBuilder()->add('page.pageID IN (SELECT pageID FROM wcf'.WCF_N.'_page_content WHERE content LIKE ?)', array('%'.$this->content.'%'));
+                       $this->objectList->getConditionBuilder()->add('page.pageID IN (SELECT pageID FROM wcf'.WCF_N.'_page_content WHERE content LIKE ?)', ['%'.$this->content.'%']);
                }
                if (!empty($this->applicationPackageID)) {
-                       $this->objectList->getConditionBuilder()->add('page.applicationPackageID = ?', array($this->applicationPackageID));
+                       $this->objectList->getConditionBuilder()->add('page.applicationPackageID = ?', [$this->applicationPackageID]);
                }
                if ($this->pageType == 'static') {
-                       $this->objectList->getConditionBuilder()->add('page.pageType IN (?, ?, ?)', array('text', 'html', 'tpl'));
+                       $this->objectList->getConditionBuilder()->add('page.pageType IN (?, ?, ?)', ['text', 'html', 'tpl']);
                }
                else if ($this->pageType == 'system') {
-                       $this->objectList->getConditionBuilder()->add('page.pageType IN (?)', array('system'));
+                       $this->objectList->getConditionBuilder()->add('page.pageType IN (?)', ['system']);
                }
        }
        
@@ -128,13 +136,14 @@ class PageListPage extends SortablePage {
        public function assignVariables() {
                parent::assignVariables();
                
-               WCF::getTPL()->assign(array(
+               WCF::getTPL()->assign([
                        'name' => $this->name,
                        'title' => $this->title,
                        'content' => $this->content,
                        'applicationPackageID' => $this->applicationPackageID,
                        'pageType' => $this->pageType,
-                       'availableApplications' => $this->availableApplications
-               ));
+                       'availableApplications' => $this->availableApplications,
+                       'showPageAddDialog' => $this->showPageAddDialog
+               ]);
        }
 }