| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- <?php
- /**
- * The ai input inject ui view file of ai module of ZenTaoPMS.
- *
- * This view file is used to inject ai generated result into
- * input fields. Include this view file in the target forms.
- *
- * @copyright Copyright 2009-2024 禅道软件(青岛)有限公司(ZenTao Software (Qingdao) Co., Ltd. www.zentao.net)
- * @license ZPL(https://zpl.pub/page/zplv12.html) or AGPL(https://www.gnu.org/licenses/agpl-3.0.en.html)
- * @author Wenrui LI <liwenrui@easycorp.ltd>
- * @package ai
- * @link https://www.zentao.net
- */
- namespace zin;
- $this->app->loadLang('ai');
- $this->app->loadConfig('ai');
- $module = $this->app->getModuleName();
- $method = $this->app->getMethodName();
- /* Inject audit menu, called from within $inputInject(), be aware of javascript assembling abuse. */
- $auditInject = function() use($module, $method)
- {
- if(!isset($_SESSION['aiPrompt']['prompt']) || empty($_SESSION['aiPrompt']['objectId'])) return;
- $prompt = $_SESSION['aiPrompt']['prompt'];
- $objectId = $_SESSION['aiPrompt']['objectId'];
- $isAudit = isset($_SESSION['auditPrompt']) && time() - $_SESSION['auditPrompt']['time'] < 10 * 60;
- $auditScript = '';
- if(isset($this->config->ai->injectAuditButton->locations[$module][$method]))
- {
- $publishBtn = html::commonButton($this->lang->ai->promptPublish, "id='promptPublish' data-promptId=$prompt->id", 'btn btn-primary btn-wide ajax-submit');
- $targetContainer = $this->config->ai->injectAuditButton->locations[$module][$method]['action']->targetContainer;
- $injectMethod = $this->config->ai->injectAuditButton->locations[$module][$method]['action']->injectMethod;
- $auditScript = <<<JAVASCRIPT
- window.injectAuditAction = () =>
- {
- JAVASCRIPT;
- if($module == 'doc')
- {
- $actionContainerStyles = empty($this->config->ai->injectAuditButton->locations[$module][$method]['action']->containerStyles) ? '{}' : $this->config->ai->injectAuditButton->locations[$module][$method]['action']->containerStyles;
- $exitAuditButton = html::commonButton($this->lang->ai->audit->exit, "id='promptAuditExit'", 'btn');
- $auditScript .= <<<JAVASCRIPT
- const actionContainerStyles = JSON.parse('{$actionContainerStyles}');
- \$('#mainContent .titleBox').children('button,a').remove()
- \$('#mainContent .titleBox').append(`{$publishBtn}`);
- \$('#mainContent .titleBox').css(actionContainerStyles);
- \$('#mainContent .titleBox').prepend(`{$exitAuditButton}`);
- JAVASCRIPT;
- }
- else
- {
- $exitAuditButton = html::commonButton($this->lang->ai->audit->exit, "id='promptAuditExit'", 'btn btn-wide');
- $auditScript .= <<<JAVASCRIPT
- const injectHTML = `{$publishBtn} {$exitAuditButton}`;
- \$(`{$targetContainer}`)[`{$injectMethod}`](injectHTML);
- JAVASCRIPT;
- }
- $auditScript .= <<<JAVASCRIPT
- };
- window.injectAuditToolbar = () =>
- {
- JAVASCRIPT;
- $regenButton = html::linkButton('<i class="icon icon-refresh muted"></i> ' . $this->lang->ai->audit->regenerate, helper::createLink('ai', 'promptexecute', "promptId=$prompt->id&objectId=$objectId"), 'self', "id='promptRegenerate'", 'btn ghost');
- $auditButton = html::commonButton($this->lang->ai->audit->designPrompt, 'id="promptAudit" data-toggle="modal" data-type="iframe" data-url="' . helper::createLink('ai', 'promptaudit', "promptId=$prompt->id&objectId=$objectId") . '"', 'btn btn-info iframe');
- $targetContainer = $this->config->ai->injectAuditButton->locations[$module][$method]['toolbar']->targetContainer;
- $injectMethod = $this->config->ai->injectAuditButton->locations[$module][$method]['toolbar']->injectMethod;
- $buttonHTML = $isAudit ? "<div class='btn-group'>$regenButton $auditButton</div>" : $regenButton;
- $auditScript .= <<<JAVASCRIPT
- const buttonHTML = `{$buttonHTML}`;
- JAVASCRIPT;
- $toolbarContainerStyles = empty($this->config->ai->injectAuditButton->locations[$module][$method]['toolbar']->containerStyles) ? '{}' : $this->config->ai->injectAuditButton->locations[$module][$method]['toolbar']->containerStyles;
- $auditScript .= "$(`$targetContainer`).first().$injectMethod(buttonHTML);";
- $auditScript .= <<<JAVASCRIPT
- \$('#promptAudit').attr('data-size', '{"height": 600}');
- const toolbarContainerStyles = JSON.parse('{$toolbarContainerStyles}');
- \$(`{$targetContainer}`).css(toolbarContainerStyles);
- };
- JAVASCRIPT;
- if($isAudit) $auditScript .= 'window.injectAuditAction();';
- $auditScript .= "if(typeof window.injectData !== 'undefined') {window.injectAuditToolbar();}";
- $loadingText = $this->lang->ai->execute->loading;
- $auditScript .= <<<JAVASCRIPT
- const publishButton = document.getElementById('promptPublish');
- if(publishButton)
- {
- \$(document).off('click', '#promptPublish').on('click', '#promptPublish', function(e)
- {
- e.preventDefault();
- const promptId = publishButton.dataset.promptid;
- const publishLink = document.createElement('a');
- publishLink.href = \$.createLink('ai', 'promptPublish', 'promptId=' + promptId + '&backToTestingLocation=true') + '#app=admin';
- publishLink.className = 'ajax-submit';
- publishLink.style.display = 'none';
- document.body.appendChild(publishLink);
- if(\$.apps.currentCode != 'admin')
- {
- window.addEventListener('popstate', function()
- {
- \$.apps.closeApp(\$.apps.currentCode);
- });
- }
- publishLink.click();
- });
- }
- const auditExitButton = document.getElementById('promptAuditExit');
- if(auditExitButton)
- {
- \$(document).off('click', '#promptAuditExit').on('click', '#promptAuditExit', function(e)
- {
- e.preventDefault();
- const promptId = publishButton.dataset.promptid;
- const exitLink = document.createElement('a');
- exitLink.href = \$.createLink('ai', 'promptAudit', 'promptId=' + promptId + '&objectId=0' + '&exit=true') + '#app=admin';
- exitLink.style.display = 'none';
- document.body.appendChild(exitLink);
- exitLink.click();
- /* TODO: find a way to close app. */
- if(\$.apps.currentCode != 'admin') \$.apps.closeApp(\$.apps.currentCode);
- });
- }
- const regenButton = document.getElementById('promptRegenerate');
- if(regenButton)
- {
- regenButton.addEventListener('click', e =>
- {
- \$('body').attr('data-loading', `{$loadingText}`);
- \$('body').addClass('load-indicator loading');
- window.sessionStorage.setItem('ai-prompt-regen', true);
- });
- }
- JAVASCRIPT;
- }
- h::globalJS("(() => {requestAnimationFrame(() => {{$auditScript}});})();");
- };
- /* Inject input data. */
- $inputInject = function() use($module, $method, &$auditInject)
- {
- if(!isset($this->config->ai->availableForms[$module]) || !in_array($method, $this->config->ai->availableForms[$module])) return;
- if(isset($_SESSION['aiInjectData']) && isset($_SESSION['aiInjectData'][$module]) && isset($_SESSION['aiInjectData'][$module][$method])) $injectData = $_SESSION['aiInjectData'][$module][$method];
- if(empty($injectData)) return;
- jsVar('window.injectData', $injectData);
- unset($_SESSION['aiInjectData'][$module]);
- $this->app->loadLang('ai');
- h::globalJS(<<<JAVASCRIPT
- (() => {
- window.injectToInputElement = (inputName, data, index, tries = 0) =>
- {
- let name = inputName;
- if(typeof index !== 'undefined') name = name + '[' + index + ']';
- const inputEl = \$('[name="' + name + '"]');
- /* Retry if input is not found, sometimes form renders late. */
- if(!inputEl.length && tries < 5) return setTimeout(() => window.injectToInputElement(inputName, data, index, ++tries), 1000);
- const inputType = inputEl.prop('nodeName');
- switch(inputType) // Contains case fallthroughs, on purpose.
- {
- case 'ZEN-EDITOR':
- /* Set Zen Editor content with its exposed method, loop till editor is ready. */
- const zenEditorEl = inputEl.get().pop();
- const setZenEditorData = () =>
- {
- try
- {
- zenEditorEl.setHTML(data).catch(_ => setTimeout(setZenEditorData, 100));
- }
- catch(_)
- {
- setTimeout(setZenEditorData, 100);
- }
- };
- setZenEditorData();
- break;
- case 'INPUT':
- /* Watch out for zui date pickers. */
- if(inputEl.hasClass('pick-value'))
- {
- if(inputEl.parent().hasClass('date-picker'))
- {
- if(inputEl.parent().parent().data().hasOwnProperty('zuiDatetimepicker'))
- {
- inputEl.zui('dateTimePicker').\$.setValue(data);
- break;
- }
- if(inputEl.parent().parent().data().hasOwnProperty('zuiDatepicker'))
- {
- inputEl.zui('datePicker').\$.setValue(data);
- break;
- }
- }
- }
- case 'TEXTAREA':
- /* Textareas might be controlled by KindEditors. */
- if(typeof KindEditor !== 'undefined' && KindEditor.instances.length)
- {
- const editorInstance = KindEditor.instances.find(e => e.srcElement.attr('name') == name);
- if(editorInstance)
- {
- if(data === null) data = '';
- /* Set editor content and sync with textarea. */
- editorInstance.html(data);
- editorInstance.sync();
- break;
- }
- }
- default:
- /* For normal inputs, just set the value is enough. */
- inputEl.val(data);
- break;
- }
- }
- window.inject = (obj) =>
- {
- for(const key in obj)
- {
- window.dealWithSpecialInputType(key, obj[key]);
- if(Array.isArray(obj[key]))
- {
- const isStartWith0 = \$('[name="' + key + '[0]' + '"]').length;
- const arr = obj[key];
- for(let i = 0; i < arr.length; i++)
- {
- for(const key in arr[i])
- {
- window.injectToInputElement(key, arr[i][key], isStartWith0 ? i : i + 1);
- }
- }
- }
- else if(typeof obj[key] === 'Object')
- {
- inject(obj[key]);
- }
- else
- {
- window.injectToInputElement(key, obj[key])
- }
- }
- }
- window.dealWithSpecialInputType = (key, value) =>
- {
- if(key === 'steps')
- {
- const steps = document.getElementById('steps');
- if(!steps) return;
- if(value.length > steps.children.length)
- {
- const gap = value.length - steps.children.length;
- for(let i = 0; i < gap; i++)
- {
- const addButton = document.querySelector('#steps > tr:last-child > .step-actions button:first-child');
- if(!addButton) return;
- addButton.click();
- }
- }
- }
- }
- requestAnimationFrame(() =>
- {
- try
- {
- const data = JSON.parse(window.injectData);
- if(!data) return;
- window.inject(data);
- zui.Messager.show({content: '{$this->lang->ai->dataInject->success}', type: 'success'});
- }
- catch(e)
- {
- zui.Messager.show({content:'{$this->lang->ai->dataInject->fail}', type: 'danger'});
- console.error(e);
- }
- finally
- {
- /* Set injected in oreder to cancel loading class on object view (see ./promptmenu.html.php). */
- sessionStorage.setItem('ai-prompt-data-injected', true);
- const container = window.frameElement?.closest('.load-indicator');
- if(container && container.dataset.loading)
- {
- sessionStorage.removeItem('ai-prompt-data-injected');
- delete container.dataset.loading;
- container.classList.remove('loading');
- container.classList.remove('no-delay');
- }
- }
- });
- })();
- JAVASCRIPT
- );
- $auditInject();
- };
- $inputInject();
|