瀏覽代碼

#2304 Wiki functionality: edit block - lang switcher

Alex Trofimov 6 年之前
父節點
當前提交
5a2851ffa5

+ 104 - 24
inc/classes/BxDolWiki.php

@@ -155,6 +155,7 @@ class BxDolWiki extends BxDolFactory implements iBxDolFactoryObject
             'edit' => 'allow_edit_for_levels',
             'delete-version' => 'allow_delete_for_levels',
             'delete-block' => 'allow_delete_for_levels',
+            'get-traaslation' => 'allow_translate_for_levels',
             'translate' => 'allow_translate_for_levels',
             'history' => true,
             'unsafe' => 'allow_unsafe_for_levels',
@@ -172,54 +173,133 @@ class BxDolWiki extends BxDolFactory implements iBxDolFactoryObject
         return $oAcl->isMemberLevelInSet($this->_aObject[$aTypes[$sType]], $iProfileId); 
     }
 
-    public function actionEdit ()
+    public function actionGetTranslation ()
     {
-        $aWikiVer = $this->_oQuery->getBlockContent ((int)bx_get('block_id'), bx_lang_name());
-        unset($aWikiVer['notes']);
+        $aWikiVer = $this->_oQuery->getBlockContent ((int)bx_get('block_id'), bx_get('lang'), false, false);
         if (!$aWikiVer)
-            $aWikiVer = array('block_id' => (int)bx_get('block_id'));
+            return array('code' => 1, 'msg' => 'no translation was found');
+        else
+            return array('code' => 0, 'lang' => $aWikiVer['lang'], 'content' => $aWikiVer['content'], 'block_id' => $aWikiVer['block_id']);
+    }
 
+    public function actionEdit ()
+    {
+        $iBlockId = (int)bx_get('block_id');
+
+        // get latest revision for block with current lang
+        $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, bx_lang_name());
+        unset($aWikiVer['notes']); // unset notes since we need this field empty in the form
+        if (!$aWikiVer) // check for new block, so initialize with default values
+            $aWikiVer = array('block_id' => $iBlockId);
+
+        // init form object
         $oForm = BxDolForm::getObjectInstance('sys_wiki', 'sys_wiki_edit');
         if (!$oForm)
             return _t('_sys_txt_error_occured');
+
+        if (isset($oForm->aInputs['lang']))
+            $oForm->aInputs['lang']['values'] = $this->getLangsForInput ($aWikiVer['block_id']);
+
         $oForm->initChecker($aWikiVer);
         if (!$oForm->isSubmittedAndValid()) {
+            // display form
             return BxDolTemplate::getInstance()->parseHtmlByName('wiki_form.html', array(
                 'form' => $oForm->getCode(),
-                'block_id' => (int)bx_get('block_id'),
+                'block_id' => $iBlockId,
                 'wiki_action_uri' => $this->getWikiUri(),
             ));
         } 
         else {
-            // get previous revision with priority for current language
-            $aWikiVer = $this->_oQuery->getBlockContent ((int)bx_get('block_id'), $oForm->getCleanValue('lang'));
+            $sLang = $oForm->getCleanValue('lang');
 
-            // increase revision for particular language or start with first revision
-            $sRev = $aWikiVer && $oForm->getCleanValue('lang') == $aWikiVer['lang'] ? $aWikiVer['revision'] + 1 : 1;
-
-            // detect main language flag
-            $bMainLang = 0;
-            if ($aWikiVer && $oForm->getCleanValue('lang') == $aWikiVer['lang']) // when revision is increased (language matches) - copy this flag from previous revision
-                $bMainLang = $aWikiVer['main_lang'];
-            elseif (!$aWikiVer) // when it's first revision and no translations - start with 1st revision
-                $bMainLang = 1;
+            // get previous revision with priority for current language
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
 
-            // detect 'unsafe' flag
-            $bUnsafe = 0;
-            if ($aWikiVer) // 
-                $bUnsafe = $aWikiVer['unsafe'];
-            elseif (!$aWikiVer)
-                $bUnsafe = $this->isAllowed('unsafe') ? 1 : 0;
+            $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
+            $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
+            $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
 
+            // insert new revision
+            $iTime = time();
             $sId =  $oForm->insert(array(
-                'added' => time(), 
+                'added' => $iTime, 
                 'revision' => $sRev,
                 'main_lang' => $bMainLang, 
                 'profile_id' => bx_get_logged_profile_id(),
                 'unsafe' => $bUnsafe,
             ));
-            return array('code' => 0, 'action' => 'Reload', 'block_id' => $aWikiVer['block_id']);
+
+            // process translations if available
+            if (($sTranslations = bx_get('translations')) && ($aTranslations = json_decode($sTranslations, true))) {
+                foreach ($aTranslations as $sLang => $sContent) {
+                    if ($sLang == $oForm->getCleanValue('lang'))
+                        continue;
+
+                    // get previous revision with priority for current language
+                    $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sLang);
+
+                    $sRev = $this->getFieldRev ($oForm, $sLang, $aWikiVer);
+                    $bMainLang = $this->getFieldMainLangFlag ($oForm, $sLang, $aWikiVer);
+                    $bUnsafe = $this->getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer);
+
+                    // insert new revision
+                    $sId =  $oForm->insert(array(
+                        'added' => $iTime, 
+                        'revision' => $sRev,
+                        'main_lang' => $bMainLang, 
+                        'profile_id' => bx_get_logged_profile_id(),
+                        'unsafe' => $bUnsafe,
+                        'lang' => $sLang,
+                        'content' => $sContent,
+                    ));
+                }
+            }
+
+            return array('code' => 0, 'actions' => array('Reload', 'ClosePopup'), 'block_id' => $aWikiVer['block_id']);
+        }
+    }
+
+    protected function getFieldRev ($oForm, $sLang, $aWikiVer) {
+        // increase revision for particular language or start with first revision
+        return $aWikiVer && $sLang == $aWikiVer['lang'] ? $aWikiVer['revision'] + 1 : 1;
+    }
+
+    protected function getFieldMainLangFlag ($oForm, $sLang, $aWikiVer) {
+        // detect main language flag
+        if ($aWikiVer && $sLang == $aWikiVer['lang']) 
+            return $aWikiVer['main_lang']; // when revision is increased (language matches) - copy this flag from previous revision
+        elseif (!$aWikiVer) 
+            return 1; // when it's first revision and no translations - start as main language
+        else
+            return 0;
+    }
+
+    protected function getFieldUnsafeFlag ($oForm, $sLang, $aWikiVer) {
+
+        if ($aWikiVer && $sLang == $aWikiVer['lang'] && !$aWikiVer['unsafe'])
+            return 0; // copy 'unsafe' from previous revision only when unsafe = 0
+        else
+            return $this->isAllowed('unsafe') ? 1 : 0; // in other cases - check permissions
+    }
+
+    protected function getLangsForInput ($iBlockId)
+    {
+        // get main lang update time
+        $aWikiVerMain = $this->_oQuery->getBlockContent ($iBlockId, 'neverhood');
+        $iUpdatedMainLang = $aWikiVerMain ? $aWikiVerMain['added'] : 0;
+
+        // generate values for radio set
+        $aLangs = BxDolLanguages::getInstance()->getLanguages(false, false);
+        foreach ($aLangs as $sKey => $sLang) {
+            $aWikiVer = $this->_oQuery->getBlockContent ($iBlockId, $sKey, false, false);
+            $sMainLang = $aWikiVer && $aWikiVer['main_lang'] ? '★' : '';
+            $sComment = !$aWikiVer ? _t('_sys_wiki_lang_missing') : bx_time_js($aWikiVer['added']);
+            if (!$aWikiVer || $iUpdatedMainLang > $aWikiVer['added'])
+                $aLangs[$sKey] = _t('_sys_wiki_lang_mask_warn', $sLang, $sMainLang, $sComment);
+            else
+                $aLangs[$sKey] = _t('_sys_wiki_lang_mask', $sLang, $sMainLang, $sComment);
         }
+        return $aLangs;
     }
 }
 

+ 65 - 7
inc/js/classes/BxDolWiki.js

@@ -12,7 +12,9 @@ function BxDolWiki (sObject, eContainer, oOptions) {
     this._sObject = sObject;
     this._eCont = eContainer;
     this._sActionUrl = sUrlRoot + 'r.php?_q=' + this._oOptions.wiki_action_uri + '-action/';
-    this.bindEvents();
+    this._sCurrentLang = this._oOptions['lang'];
+    this._oTranslations = {};
+    this.bindEvents();    
 }
 
 BxDolWiki.prototype.bindEvents = function () {
@@ -39,7 +41,8 @@ BxDolWiki.prototype.removePopup = function (iBlockId) {
 }
 
 BxDolWiki.prototype.onEdit = function () {
-
+    
+    var self = this;
     var sActionUrl = bx_append_url_params(this._sActionUrl + 'edit', {
         block_id: this._oOptions.block_id
     });
@@ -51,6 +54,49 @@ BxDolWiki.prototype.onEdit = function () {
     $(window).dolPopupAjax({url: sActionUrl});
 };
 
+BxDolWiki.prototype.getTranslations = function () {
+    return this._oTranslations;
+}
+
+BxDolWiki.prototype.loadingForm = function (b) {
+    bx_loading($('#bx-form-element-content'), b);
+    var eForm = $("#bx-wiki-form-" + this._oOptions.block_id);
+    if (b)
+        $(eForm).find("textarea[name=content]").val('');
+    $(eForm).find("textarea[name=content],input[name=lang],button[type=submit]").prop('disabled', b);
+}
+
+BxDolWiki.prototype.onChangeLangSelector = function (e) {
+    var self = this;
+    var eContent = $("#bx-wiki-form-" + this._oOptions.block_id + " textarea[name=content]");
+    var sLangNew = $(e).val();
+
+    // save current translation
+    this._oTranslations[this._sCurrentLang] = eContent.val();
+
+    if ('undefined' === typeof(this._oTranslations[sLangNew])) {
+        // no saved translation was found - get from server
+        self.loadingForm(true);
+        var sUrl = bx_append_url_params(sUrlRoot + 'r.php?_q=' + this._oOptions.wiki_action_uri + '-action/get-translation', {
+            block_id: this._oOptions.block_id,
+            lang: sLangNew,
+        });
+        $.getJSON(sUrl, function (oData) {
+            if ('undefined' !== typeof(oData.content))
+                eContent.val(oData.content);
+            // save current language
+            self._sCurrentLang = sLangNew;
+            self.loadingForm(false);
+        });
+    } 
+    else {
+        // saved translation was found - switch to it immediately
+        eContent.val(this._oTranslations[sLangNew]);
+        // save current language
+        this._sCurrentLang = sLangNew;
+    }
+};
+
 BxDolWiki.prototype.onDeleteVersion = function () {
     console.log("onDeleteVersion:" + this._sObject);
 };
@@ -68,13 +114,23 @@ BxDolWiki.prototype.onTranslate = function () {
 };
 
 BxDolWiki.prototype.processResponce = function (oResponce) {
-    if ('undefined' === typeof(oResponce.action))
-        return;    
-    if ('function' == typeof(this['action' + oResponce.action]))
-        this['action' + oResponce.action](oResponce);
+    var self = this;
+
+    if ('undefined' === typeof(oResponce.actions))
+        return;
+
+    if ('string' === typeof(oResponce.actions))
+        oResponce.actions = [oResponce.actions];
+
+    if ('object' === typeof(oResponce.actions)) {
+        $.each(oResponce.actions, function () {
+            if ('function' == typeof(self['action' + this]))
+                self['action' + this](oResponce);
+        });
+    }
 }
 
-BxDolWiki.prototype.actionReload = function (oResponce) {
+BxDolWiki.prototype.actionClosePopup = function (oResponce) {
     var self = this;
     if ($(".bx-popup-active").size())
         $(".bx-popup-active").dolPopupHide({onHide:function (){
@@ -82,6 +138,8 @@ BxDolWiki.prototype.actionReload = function (oResponce) {
         }})
     else
         this.removePopup();
+}
+BxDolWiki.prototype.actionReload = function (oResponce) {
     loadDynamicBlock(oResponce.block_id, document.location.href);
 }
 

+ 1 - 1
install/sql/system.sql

@@ -3203,7 +3203,7 @@ INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `c
 ('sys_privacy_group_custom', 'system', 'do_cancel', '_sys_form_ps_gc_input_caption_do_cancel', '', 0, 'button', '_sys_form_ps_gc_input_caption_system_do_cancel', '', '', 0, 0, 0, 'a:2:{s:7:"onclick";s:45:"$(''.bx-popup-applied:visible'').dolPopupHide()";s:5:"class";s:22:"bx-def-margin-sec-left";}', '', '', '', '', '', '', '', 0, 0),
 
 ('sys_wiki', 'system', 'block_id', '', '', 0, 'hidden', '', '_sys_form_wiki_input_caption_block_id', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 0, 0),
-('sys_wiki', 'system', 'lang', '', '', 0, 'select', '', '_sys_form_wiki_input_caption_lang', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
+('sys_wiki', 'system', 'lang', '', '', 0, 'radio_set', '', '_sys_form_wiki_input_caption_lang', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
 ('sys_wiki', 'system', 'content', '', '', 0, 'textarea', '', '_sys_form_wiki_input_caption_content', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
 ('sys_wiki', 'system', 'notes', '', '', 0, 'text', '', '_sys_form_wiki_input_caption_notes', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
 ('sys_wiki', 'system', 'do_submit', '_sys_submit', '', 0, 'submit', '_sys_form_wiki_input_caption_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),

+ 4 - 0
modules/boonex/english/data/langs/system/en.xml

@@ -2290,6 +2290,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_display_wiki_edit"><![CDATA[Wiki Edit]]></string>
 	<string name="_sys_form_wiki_input_caption_block_id"><![CDATA[Block ID]]></string>
 	<string name="_sys_form_wiki_input_caption_lang"><![CDATA[Language]]></string>
+	<string name="_sys_form_wiki_input_caption_lang_info"><![CDATA[★ - main language, red - outdated or missing translation]]></string>
 	<string name="_sys_form_wiki_input_caption_content"><![CDATA[Content]]></string>
 	<string name="_sys_form_wiki_input_caption_notes"><![CDATA[Notes]]></string>
 	<string name="_sys_form_wiki_input_caption_submit"><![CDATA[Submit]]></string>
@@ -3110,5 +3111,8 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_wiki_error_page_exists"><![CDATA[Page with such name({0}) already exists]]></string>
 	<string name="_sys_wiki_error_missing_wiki_object"><![CDATA[Wiki object ({0}) wasn't found]]></string>
     <string name="_sys_wiki_error_action_not_allowed"><![CDATA[Wiki object ({1}) action ({0}) isn't allowed]]></string>
+    <string name="_sys_wiki_lang_mask"><![CDATA[{0} {1} - <span>{2}</span>]]></string>
+    <string name="_sys_wiki_lang_mask_warn"><![CDATA[{0} {1} - <span style="color:red;">{2}</span>]]></string>
+    <string name="_sys_wiki_lang_missing"><![CDATA[missing]]></string>
 	
 </resources>

+ 4 - 0
modules/boonex/russian/data/langs/system/ru.xml

@@ -2279,6 +2279,7 @@
     <string name="_sys_form_display_wiki_edit"><![CDATA[Вики: редактирование]]></string>
 	<string name="_sys_form_wiki_input_caption_block_id"><![CDATA[Идентификатор блока]]></string>
 	<string name="_sys_form_wiki_input_caption_lang"><![CDATA[Язык]]></string>
+    <string name="_sys_form_wiki_input_caption_lang_info"><![CDATA[★ - основной язык, красным помечен отсутствующий или устаревший перевод]]></string>
 	<string name="_sys_form_wiki_input_caption_content"><![CDATA[Содержимое]]></string>
 	<string name="_sys_form_wiki_input_caption_notes"><![CDATA[Заметки]]></string>
 	<string name="_sys_form_wiki_input_caption_submit"><![CDATA[Сохранить]]></string>
@@ -3090,5 +3091,8 @@
 	<string name="_sys_wiki_error_page_exists"><![CDATA[Страница с таким именем ({0}) уже существует]]></string>
     <string name="_sys_wiki_error_missing_wiki_object"><![CDATA[Вики объект ({0}) не найден]]></string>
     <string name="_sys_wiki_error_action_not_allowed"><![CDATA[Не разрешенное действие ({0}) для вики объекта ({1})]]></string>
+    <string name="_sys_wiki_lang_mask"><![CDATA[{0} {1} - {2}]]></string>
+    <string name="_sys_wiki_lang_mask_warn"><![CDATA[{0} {1} - <span style="color:red;">{2}</span>]]></string>
+    <string name="_sys_wiki_lang_missing"><![CDATA[отсутствует]]></string>
 
 </resources>

+ 1 - 1
modules/boonex/wiki/install/sql/enable.sql

@@ -2,7 +2,7 @@
 -- Wiki object
 
 INSERT INTO `sys_objects_wiki` (`object`, `uri`, `title`, `module`, `allow_add_for_levels`, `allow_edit_for_levels`, `allow_delete_for_levels`, `allow_translate_for_levels`, `allow_unsafe_for_levels`, `override_class_name`, `override_class_file`) VALUES
-('bx_wiki', 'wiki', '_bx_wiki_object_title', 'system', 192, 192, 192, 192, 192, '', '');
+('bx_wiki', 'wiki', '_bx_wiki_object_title', 'system', 192, 192, 192, 192, 0, '', '');
 
 -- Permalinks
 

+ 2 - 6
template/scripts/BxBaseFormView.php

@@ -1560,8 +1560,7 @@ BLAH;
     /**
      * Generate Label Element
      *
-     * @param  string $sLabel   Text of the Label
-     * @param  string $sInputID Dependant Input Element ID
+     * @param  string $aInput   input array
      * @return string HTML code
      */
     function genLabel(&$aInput)
@@ -1569,12 +1568,9 @@ BLAH;
         if (!isset($aInput['label']) or empty($aInput['label']))
             return '';
 
-        $sLabel   = $aInput['label'];
         $sInputID = $this->getInputId($aInput);
 
-        $sRet = '<label for="' . $sInputID . '">' . bx_process_output($sLabel) . '</label>';
-
-        return $sRet;
+        return '<label for="' . $sInputID . '">' . bx_process_output($aInput['label']) . '</label>';
     }
 
     function genInfoIcon($sInfo)

+ 8 - 0
template/scripts/BxBaseFormWiki.php

@@ -22,6 +22,14 @@ class BxBaseFormWiki extends BxTemplFormView
             $this->aInputs['content']['code'] = true;
     }
 
+    function genLabel(&$aInput)
+    {
+        if (isset($aInput['label']) && $aInput['label'] && 'lang' == $aInput['name']) {
+            $sInputID = $this->getInputId($aInput);
+            return '<label for="' . $sInputID . '">' . $aInput['label'] . '</label>';
+        }
+        return parent::genLabel($aInput);
+    }
 }
 
 /** @} */

+ 1 - 0
template/scripts/BxBaseServiceWiki.php

@@ -136,6 +136,7 @@ class BxBaseServiceWiki extends BxDol
             'info' => bx_time_js($aWikiVer['added']), // 'TODO: On right - Last modified time and List of missing and outdated translations. History and Last modified time should be controlled by regular menu privacy, while other actions should have custom privacy for particular wiki object',
             'options' => json_encode(array(
                 'block_id' => $sBlockId,
+                'lang' => $aWikiVer['lang'],
                 'wiki_action_uri' => $oWikiObject->getWikiUri(),
             )),
         ));

+ 7 - 1
template/wiki_form.html

@@ -5,8 +5,9 @@
     $(document).ready(function () {
         $("#bx-wiki-form-__block_id__ form").ajaxForm({
             url: sUrlRoot + 'r.php?_q=__wiki_action_uri__-action/edit',
-            beforeSubmit: function (formData, jqForm, options) {
+            beforeSubmit: function (formData, $form, options) {
                 bx_loading($("#bx-wiki-form-__block_id__ form"), true);
+                formData.push({name: 'translations', value: JSON.stringify(window.glBxDolWiki__block_id__.getTranslations())});
             },
             success: function (data) {
                 if ('{' == data[0]) {
@@ -18,5 +19,10 @@
                 }
             }
         });
+
+        $("#bx-wiki-form-__block_id__ input[name=lang]").change(function() {
+            window.glBxDolWiki__block_id__.onChangeLangSelector(this);
+            return false;
+        });
     });
 </script>