| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625 |
- if(!window.docAppData) window.docAppData = {
- lastAppUrl: '',
- originalDocumentTitle: document.title,
- documentTitleSuffix: ' - ' + document.title.split(' - ').pop(),
- currentUser: null,
- currentSpaceType: '',
- userPrivs: {},
- };
- const docAppData = window.docAppData;
- let savingDocData = {};
- let docBasicModal = {};
- let currentDocApp = null;
- window.setZentaoSlashMenu = function(menus, title, position)
- {
- if(!menus?.length) return;
- const slashMenus = menus.map(menu =>
- {
- if(menu.subMenu)
- {
- menu.subMenu = menu.subMenu.map(subMenu => {
- subMenu.action = function (context) {
- zui.Modal.open({
- size: subMenu.modalSize ? subMenu.modalSize : 'lg',
- url: $.createLink(subMenu.module, subMenu.method, subMenu.params)
- });
- }
- return subMenu;
- });
- }
- else
- {
- if(menu.key == 'gantt' && !menu.isModal)
- {
- menu.action = function (context) {
- const doc = getDocApp().doc;
- $.ajaxSubmit({
- url: $.createLink(menu.module, menu.method, menu.params),
- data: {templateID: doc.data.id}
- });
- }
- }
- else
- {
- menu.action = function (context) {
- zui.Modal.open({
- size: menu.modalSize ? menu.modalSize : 'lg',
- url: $.createLink(menu.module, menu.method, menu.params)
- });
- }
- }
- }
- return menu;
- });
- slashMenus.unshift({ groupName: title});
- zui.Editor.setSlashMenu(slashMenus, {before: position, reset: true});
- zui.Editor.setGlobalConfig({slashMenuStyles: [`link:${$.libRoot}zui.zentao.css`]});
- }
- /**
- * 更多菜单操作。
- * More menu action.
- *
- * @param {MoreMenuItem} menu
- */
- window.moreMenuAction = function(menu)
- {
- if (menu.module && menu.method && menu.params)
- {
- if(menu.key == 'gantt' && !menu.isModal)
- {
- const doc = getDocApp().doc;
- $.ajaxSubmit({
- url: $.createLink(menu.module, menu.method, menu.params),
- data: {templateID: doc.data.id}
- });
- }
- else {
- zui.Modal.open({
- size: menu.modalSize ? menu.modalSize : 'lg',
- url: $.createLink(menu.module, menu.method, menu.params)
- });
- }
- }
- }
- /* 获取 ZentaoList 块属性。 */
- function getZentaoListProps(type, blockID, props)
- {
- if(props && props.isTemplate) blockID = '__TML_ZENTAOLIST__' + blockID;
- const zentaoListLang = getLang('zentaoList');
- const exportUrl = `${location.origin}${$.createLink('doc', 'ajaxExportZentaoList', `blockID=${blockID}`)}`;
- const title = [(zentaoListLang ? zentaoListLang[type] : type), getLang('list')].join(config.clientLang.includes('zh') ? '' : ' ');
- const fetcher = `${location.origin}${$.createLink('doc', 'zentaoList', `type=${type}&blockID=${blockID}`)}`;
- return $.extend({}, props,
- {
- title: title,
- fetcher: fetcher,
- clearBeforeLoad: false
- }, type === 'gantt' ? {
- fetcher: fetcher,
- export: [{type: 'link', props: {text: title, href: exportUrl}}]
- } : {
- exportUrl: exportUrl,
- });
- }
- /* 更新禅道列表。*/
- window.updateZentaoList = function(blockID, props)
- {
- const $block = $('#docApp').find(`.zentao-list[data-id="${blockID}"]`);
- if(!$block.length) return false;
- getDocApp().editor.$.updateBlock($block[0], props);
- };
- /* 替换禅道列表。*/
- window.replaceZentaoList = function(oldBlockID, newType, newblockID, props)
- {
- return updateZentaoList(oldBlockID, {content: getZentaoListProps(newType, newblockID, props), renderID: $.guid++});
- };
- /* 插入禅道列表。*/
- window.insertZentaoList = function(type, blockID, props, replaceBlockID)
- {
- if(Number(replaceBlockID)) return replaceZentaoList(replaceBlockID, type, blockID, props);
- getDocApp().editor.$.insertCustom(getZentaoListProps(type, blockID, props));
- };
- /* 从编辑器删除禅道列表。*/
- window.deleteZentaoList = function(blockID)
- {
- const $block = $('#docApp').find(`.zentao-list[data-id="${blockID}"]`);
- if(!$block.length) return false;
- getDocApp().editor.$.deleteBlock($block[0]);
- };
- /* 重新载入禅道列表。*/
- window.reloadZentaoList = function(blockID)
- {
- $('#docApp').find(`.zentao-list[data-id="${blockID}"]`)
- .closest('.lazy-content')
- .trigger('loadContent');
- };
- /**
- * Get doc app instance.
- * 获取文档应用组件实例。
- *
- * @returns {object}
- */
- window.getDocApp = function()
- {
- if(!currentDocApp)
- {
- const $docApp = $('#docApp');
- const docApp = $docApp.data('zui.DocApp') || $docApp.data('zui.DocViewer');
- currentDocApp = docApp ? docApp.$ : null;
- }
- return currentDocApp;
- }
- /**
- * 获取语言项,如果没有设置 key,则获取整个语言项对象,语言项定义在 module/doc/ui/app.html.php 的 $langData 中。
- * Get language item, if key is not set, return the whole language object, language items are defined in $langData in module/doc/ui/app.html.php.
- *
- * @param {string} key
- * @param {array|string|object} args
- */
- window.getLang = function(key, args)
- {
- if(!docAppData.docLangData)
- {
- const docApp = getDocApp();
- docAppData.docLangData = docApp ? docApp.props.langData : {};
- }
- if(typeof key !== 'string') return docAppData.docLangData;
- const value = docAppData.docLangData[key];
- if(value === undefined) return;
- if(args)
- {
- args = Array.isArray(args) ? args : [args];
- args.unshift(value);
- return zui.formatString.apply(null, args);
- }
- return value;
- }
- /**
- * 检查是否有指定的权限,权限定义在 module/doc/ui/app.html.php 的 $privs 中。
- * Check if the specified privilege exists, privileges are defined in $privs in module/doc/ui/app.html.php.
- * @param {string} priv
- */
- window.hasPriv = function(priv, value)
- {
- const setting = docAppData.userPrivs[priv];
- return value !== undefined ? setting === value : !!setting;
- }
- /**
- * 处理文档应用销毁事件,销毁文档基本信息对话框。
- * Handle the doc app destroy event, destroy the doc basic info dialog.
- */
- function handleDocAppDestroy()
- {
- if(docBasicModal.current)
- {
- docBasicModal.current.destroy();
- docBasicModal = {};
- }
- }
- function isApiLib(lib, docApp)
- {
- if(docApp && docApp.spaceType === 'api') return true;
- if(typeof lib === 'number') lib = getDocApp().getLib(lib);
- if(!lib)
- {
- docApp = docApp || getDocApp();
- if(!docApp) return false;
- if(docApp.spaceType === 'api') return true;
- lib = docApp.lib;
- }
- return lib && lib.data.type === 'api';
- }
- function isApiDoc(doc)
- {
- const docApp = getDocApp();
- if(docApp && docApp.spaceType === 'api') return true;
- if(typeof doc !== 'object' && docApp) doc = docApp.getDoc(doc);
- if(doc && doc.api !== undefined) return doc.api;
- const id = typeof doc === 'object' ? doc.id : doc;
- return String(id).startsWith('api.');
- }
- /**
- * 处理对话框的操作,执行文档应用实例上的方法。
- * Process dialog actions, execute methods on the doc app instance.
- *
- * @param {string|array|object} action
- * @param {object} docApp
- */
- function processDocAppAction(action, docApp)
- {
- docApp = docApp || getDocApp();
- if(typeof action === 'string')
- {
- action = {call: action};
- }
- if(Array.isArray(action))
- {
- if(typeof action[0] !== 'string')
- {
- action.forEach((act) => processDocAppAction(act, docApp));
- return;
- }
- action = {call: action[0], args: action.slice(1)};
- }
- if(!action.mode && action.call.includes(':'))
- {
- const parts = action.call.split(':');
- action.mode = parts[0];
- action.call = parts[1];
- }
- if(action.mode && action.mode !== docApp.mode) return;
- const method = zui.deepGet(docApp, action.call);
- if(typeof method === 'function') method.apply(docApp, action.args);
- }
- /**
- * 检查空间是否可以进行修改操作,如果不指定空间则判断当前空间。
- * Check if the space can be modified, if the space is not specified, check the current space.
- *
- * @param {object|number} space
- */
- window.canModifySpace = function(space)
- {
- const docApp = getDocApp();
- if(!docApp && !space) return false;
- space = typeof space !== 'object' ? docApp.getSpace(space) : space;
- return space && space.canModify !== false;
- }
- /*
- * 修改 Ajax 表单提交后的默认处理方法,改为处理文档应用的操作。
- * Modify the default processing method after Ajax form submission to process the actions of the doc app.
- */
- zui.AjaxForm.DEFAULT.onResult = function(res)
- {
- const docApp = getDocApp();
- if(docApp && res.docApp)
- {
- /* 请求响应对象中的 docApp 属性定义了如何进行后续操作。 */
- processDocAppAction(res.docApp, docApp);
- delete res.docApp;
- delete res.load;
- delete res.locate;
- delete res.callback;
- }
- };
- let lastViewedSpaceHome = '';
- let lastViewedSpace = '';
- let lastViewedLib = '';
- /**
- * 向服务器提交最新访问的文档对象。
- * Post last viewed data to server.
- *
- * @param {object} location Doc App location info.
- * @returns void
- */
- function postLastViewedToServer(location)
- {
- if(!location) return;
- const postData = {};
- const {spaceType, spaceID, libID} = location;
- if(spaceType && spaceType !== lastViewedSpaceHome)
- {
- lastViewedSpaceHome = spaceType;
- postData.lastViewedSpaceHome = spaceType;
- }
- if(spaceID && spaceID !== lastViewedSpace)
- {
- const realSpaceID = typeof spaceID === 'number'
- ? spaceID
- : spaceID.split('.')[1];
- if(typeof realSpaceID === 'number')
- {
- lastViewedSpace = spaceID;
- postData.lastViewedSpace = spaceID;
- }
- }
- if(libID && libID !== lastViewedLib)
- {
- lastViewedLib = libID;
- postData.lastViewedLib = libID;
- }
- if(Object.keys(postData).length) $.post($.createLink('doc', 'ajaxSetLastViewed'), postData);
- }
- /**
- * 处理文档应用界面切换事件,修改浏览器地址栏 URL 和标题。
- * Handle the doc app view switch event, modify the browser address bar URL and title.
- *
- * @param {string} mode Doc App ui mode.
- * @param {object} location Doc App location info.
- * @param {object} info Doc App view info.
- * @returns
- */
- function handleSwitchView(mode, location, info)
- {
- if(!this.element || this.element.closest('.modal')) return;
- const rawModule = config.rawModule.toLowerCase();
- const rawMethod = config.rawMethod.toLowerCase();
- const formatUrl = this.props.viewModeUrl;
- const formatOptions = $.extend({recTotal: 0, recPerPage: 20, page: 1}, location, location.pager,
- {
- mode : mode,
- rawModule : rawModule,
- rawMethod : rawMethod,
- search : encodeURIComponent(location.search || ''),
- noSpace : location.noSpace || 0,
- filterType: encodeURIComponent(location.filterType || '')
- });
- postLastViewedToServer(location);
- if(typeof formatUrl === 'function')
- {
- url = formatUrl.call(this, formatOptions);
- }
- else if(mode === 'view' || mode === 'diff')
- {
- url = $.createLink('doc', 'view', `docID=${location.docID}` + (info.data && location.docVersion && location.docVersion !== info.data.version ? `&version=${location.docVersion}` : ''));
- }
- else
- {
- url = zui.formatString(formatUrl, formatOptions).replace('&libID=0&moduleID=0&docID=0&mode=home&orderBy=id_desc&recTotal=0&recPerPage=0&pageID=1&filterType=&search=&noSpace=false', '').replace('&libID=0&moduleID=0&browseType=all¶m=&orderBy=&recTotal=0&recPerPage=20&pageID=1&mode=home&docID=0&search=', '');
- }
- if(url === docAppData.lastAppUrl) return;
- if(docAppData.lastAppUrl && !$.apps.getAppUrl().endsWith(url)) $.apps.updateAppUrl(url, info.title ? (info.title + docAppData.documentTitleSuffix) : docAppData.originalDocumentTitle);
- docAppData.lastAppUrl = url;
- if(docBasicModal.current)
- {
- docBasicModal.current.destroy();
- docBasicModal = {};
- }
- }
- function showDocBasicModal(parentID, docID, isDraft, modalType = 'doc', doc = null)
- {
- const docApp = getDocApp();
- const spaceType = docApp.spaceType;
- const spaceID = docApp.spaceID;
- const libID = docApp.libID;
- const moduleID = docApp.moduleID;
- const url = $.createLink('doc', 'setDocBasic', `objectType=${spaceType}&objectID=${spaceID}&libID=${libID}&moduleID=${moduleID}&parentID=${parentID || 0}&docID=${docID || 0}&isDraft=${isDraft ? 'yes' : 'no'}&modalType=${modalType}`);
- if(docBasicModal.doc === docID && docBasicModal.current)
- {
- docBasicModal.current.show();
- }
- else
- {
- if(docBasicModal.current) docBasicModal.current.destroy();
- docBasicModal.doc = docID;
- zui.Modal.open(
- {
- key : `${config.rawModule}-${config.rawMethod}-${spaceType}-${docID}`,
- ref : docBasicModal,
- url : url,
- destroyOnHide: !docID,
- cache : true,
- request: {
- method: "POST",
- data: {
- title: doc?.title,
- },
- error: error => {
- if(docBasicModal.current) docBasicModal.current.hide();
- showSaveFailedAlert(error);
- }
- },
- onHidden: () => {
- if(!docBasicModal.keepOnHide && docBasicModal.current) docBasicModal.current.destroy();
- },
- $onDestroy: () => {
- if(docBasicModal.current) docBasicModal = {};
- }
- });
- }
- return new Promise((resolve) => {window.docBasicModalResolver = resolve;});
- }
- window.beforeSetDocBasicInfo = function(_, form)
- {
- docBasicModal.keepOnHide = true;
- if (window.docBasicModalResolver) window.docBasicModalResolver(new FormData(form));
- zui.Modal.query('#setDocBasicForm').hide();
- return false;
- };
- function mergeDocFormData(doc, formData)
- {
- if(!doc || !formData) return;
- const keys = new Set(formData.keys());
- for(const key of keys)
- {
- const values = formData.getAll(key);
- if(!values.length) continue;
- if(key === 'module' || key === 'lib') doc[key] = +values[0];
- else doc[key] = values.length > 1 ? values : values[0];
- }
- return doc;
- }
- window.showSaveFailedAlert = function(error)
- {
- zui.Modal.alert(
- {
- title: getLang('saveDocFailed'),
- content: error instanceof Error ? error.message : String(error),
- actions: [
- {key: 'close'}
- ]
- });
- console.error('Save doc failed:', error);
- }
- /**
- * 向服务器提交新文档。
- * Submit new doc to server.
- *
- * @param {object} doc
- * @param {number} spaceID
- * @param {number} libID
- * @param {number} moduleID
- * @param {FormData} formData
- * @returns
- */
- function submitNewDoc(doc, spaceID, libID, moduleID, formData, afterCreate)
- {
- const docApp = getDocApp();
- if(docApp.isSavingDoc) return;
- docApp.isSavingDoc = true;
- $(docApp.element).find('[zui-command^="saveDoc"],[zui-command^="saveNewDoc"]').attr('disabled', true);
- const spaceType = docApp.signals.spaceType.value;
- const url = $.createLink('doc', 'create', `objectType=${spaceType}&objectID=${Math.max(spaceID, 0)}&libID=${libID}&moduleID=${moduleID}`);
- const docData =
- {
- rawContent : doc.content,
- content : doc.html,
- status : doc.status || 'normal',
- contentType: doc.contentType,
- type : doc.type || 'text',
- lib : libID,
- module : moduleID,
- parent : doc.parent,
- title : doc.title,
- keywords : doc.keywords,
- acl : 'private',
- space : spaceType,
- uid : (doc.uid || `doc${doc.id}`),
- template : doc.template
- };
- if(formData) mergeDocFormData(docData, formData);
- const getErrorMessage = (res) => {
- if(typeof res.message === 'string') return res.message;
- if(typeof res.message === 'object' && res.message && Object.values(res.message).length)
- {
- for(const x of Object.values(res.message))
- {
- if(typeof x === 'string') return x;
- if(Array.isArray(x) && x.length) return x[0];
- }
- }
- if(typeof data.error === 'string') return data.error;
- return getLang('errorOccurred');
- };
- return new Promise((resolve, reject) =>
- {
- $.post(url, docData, (res) =>
- {
- try
- {
- const data = JSON.parse(res);
- if(!checkResponse(data)) return;
- if(typeof data !== 'object' || data.result === 'fail')
- {
- throw new Error(getErrorMessage(data));
- }
- const newDoc = $.extend(doc, {id: data.id}, docData, data.doc, {status: doc.status || data.status});
- if (!newDoc.space.includes('.')) {
- newDoc.space = `${spaceType}.${docData[spaceType]}`;
- }
- resolve(newDoc);
- if(afterCreate)
- {
- docApp.load(null, null, null, {noLoading: true, picks: 'doc'}).then(() => {
- afterCreate(newDoc);
- });
- }
- }
- catch (error)
- {
- showSaveFailedAlert(error);
- reject(error);
- }
- }).fail(error => {
- resolve(false);
- showSaveFailedAlert(error);
- }).complete(() => {
- docApp.isSavingDoc = false;
- $(docApp.element).find('[zui-command^="saveDoc"],[zui-command^="saveNewDoc"]').removeAttr('disabled');
- });
- });
- }
- function submitEditDoc(doc, formData)
- {
- const url = $.createLink('doc', 'edit', `docID=${doc.id}`);
- const docApp = getDocApp();
- const docData = {status: 'normal', type: 'chapter'};
- if(formData) mergeDocFormData(docData, formData);
- return new Promise((resolve) => {
- $.post(url, docData, (res) =>
- {
- try
- {
- const data = JSON.parse(res);
- if(!checkResponse(data)) return;
- if(typeof data !== 'object' || data.result === 'fail')
- {
- let message = data.message || data.error || getLang('errorOccurred');
- if(typeof message === 'object') message = Object.values(message).map(x => Array.isArray(x) ? x.join('\n') : x).join('\n');
- throw new Error(message);
- }
- resolve(doc);
- }
- catch (error)
- {
- resolve(false);
- showSaveFailedAlert(error);
- if(!error.message) return;
- }
- }).fail(error => {
- resolve(false);
- showSaveFailedAlert(error);
- }).complete(() => {
- docApp.load(null, null, null, {noLoading: true, picks: 'doc'});
- });
- });
- }
- /**
- * 处理创建文档的操作请求,向服务器发送请求并返回创建的文档对象。
- * Handle the create doc operation request, send a request to the server and return the created doc object.
- */
- function handleCreateDoc(doc, spaceID, libID, moduleID)
- {
- return showDocBasicModal(0, 0, doc.status === 'draft', 'doc', doc).then((formData) => {
- return submitNewDoc(doc, spaceID, libID, moduleID, formData);
- });
- }
- /**
- * 处理保存文档的操作请求,向服务器发送请求并返回保存的文档对象。
- * Handle the save doc operation request, send a request to the server and return the saved doc object.
- */
- function handleSaveDoc(doc)
- {
- const docApp = getDocApp();
- if(docApp.isSavingDoc) return;
- docApp.isSavingDoc = true;
- $(docApp.element).find('[zui-command^="saveDoc"],[zui-command^="saveNewDoc"]').attr('disabled', true);
- const spaceType = doc.object ? doc.object.type : (doc.objectType || docApp.signals.spaceType.value);
- const libID = doc.libInfo ? doc.libInfo.id : (doc.lib || docApp.signals.libID.value);
- const moduleID = doc.module || docApp.signals.moduleID.value;
- const url = $.createLink('doc', 'edit', `docID=${doc.id}`);
- const docData = {
- rawContent : doc.content,
- status : doc.status || 'normal',
- contentType: doc.contentType,
- type : 'text',
- lib : libID,
- module : moduleID,
- parent : doc.parent,
- title : doc.title,
- keywords : doc.keywords,
- acl : doc.acl,
- content : doc.html,
- space : spaceType,
- uid : (doc.uid || `doc${doc.id}`),
- };
- if(Array.isArray(doc.files)) docData.files = doc.files.map(f => typeof f === 'object' ? f.id : f).join(',');
- if(doc.fromVersion) docData.fromVersion = doc.fromVersion;
- if(savingDocData[doc.id])
- {
- mergeDocFormData(docData, savingDocData[doc.id]);
- delete savingDocData[doc.id];
- }
- return new Promise((resolve) => {
- $.post(url, docData, (res) =>
- {
- try
- {
- const data = JSON.parse(res);
- if(!checkResponse(data)) return;
- if(typeof data !== 'object' || data.result === 'fail')
- {
- let message = data.message || data.error || getLang('errorOccurred');
- if(typeof message === 'object') message = Object.values(message).map(x => Array.isArray(x) ? x.join('\n') : x).join('\n');
- throw new Error(message);
- }
- doc = $.extend({}, doc, docData, data.doc);
- if(docApp.spaceType == 'quick')
- {
- resolve(false);
- const libType = docApp.lib.data.quickType;
- return loadPage($.createLink('doc', 'quick', `type=${libType}&docID=${doc.id}`));
- }
- const libID = +doc.lib;
- const lib = docApp.getLib(libID);
- if(!lib)
- {
- resolve(false);
- return loadPage($.createLink('doc', 'view', `docID=${doc.id}`));
- }
- delete doc.title;
- delete doc.keywords;
- delete doc.content;
- resolve(doc);
- }
- catch (error)
- {
- resolve(false);
- showSaveFailedAlert(error);
- if(!error.message) return;
- }
- }).fail(error => {
- resolve(false);
- showSaveFailedAlert(error);
- }).complete(() => {
- docApp.isSavingDoc = false;
- $(docApp.element).find('[zui-command^="saveDoc"],[zui-command^="saveNewDoc"]').removeAttr('disabled');
- const {id, acl, users, groups, addedBy} = doc;
- let isInEditGroups = false;
- for(let groupID of Object.values(userGroups))
- {
- if(groups.includes(groupID)) isInEditGroups = true;
- }
- if(acl == 'private' && !users.includes(docAppData.currentUser) && addedBy !== docAppData.currentUser && !isInEditGroups)
- {
- if(docApp.hasEditingDoc)
- {
- docApp.cancelEditDoc().then(() => {
- docApp.delete('doc', id);
- docApp.load(null, null, null, {noLoading: true, picks: 'doc'});
- });
- }
- else
- {
- docApp.delete('doc', id);
- docApp.load(null, null, null, {noLoading: true, picks: 'doc'});
- }
- }
- });
- });
- }
- /**
- * 检查给定的文档是否可以进行移动操作。
- * Check if the given doc can be moved.
- */
- function canMoveDoc(doc)
- {
- return !String(doc.id).startsWith('api.') && getDocApp().props.privs.moveDoc;
- }
- /**
- * 处理删除文档文件的请求。
- * Handle the request to delete the doc file.
- * @param {object} file File info object.
- * @param {object} doc Doc info object.
- */
- function deleteDocFile(file, doc)
- {
- zui.Modal.confirm(getLang('fileConfirmDelete')).then(result =>
- {
- if(!result) return;
- $.ajaxSubmit(
- {
- url: $.createLink('doc', 'deleteFile', `docID=${doc.id}&fileID=${file.id}&confirm=yes`),
- load: false,
- callback: null,
- onSuccess: (res) =>
- {
- if(res && typeof res === 'object' && res.result === 'success')
- {
- getDocApp().update('doc', $.extend({}, doc, {files: doc.files.filter(f => f.id !== file.id)}));
- zui.HistoryPanel.update({objectType: 'doc', objectID: doc.id});
- }
- }
- })
- });
- }
- /**
- * 处理重命名文件的请求。
- * Handle the request to rename the file.
- *
- * @param {object} file
- * @param {object} doc
- */
- function renameDocFile(file, doc)
- {
- let fileName = file.title;
- let extension = file.extension;
- if(extension && fileName.endsWith(`.${extension}`)) fileName = fileName.substring(0, fileName.length - extension.length - 1);
- zui.Modal.prompt({message: getLang('fileRename'), defaultValue: fileName, placeholder: fileName}).then(newName =>
- {
- if(!newName) return;
- fileName = newName;
- if(extension && fileName.endsWith(`.${extension}`))
- {
- fileName = fileName.substring(0, fileName.length - extension.length - 1);
- }
- else if(!extension && fileName.includes('.'))
- {
- extension = fileName.split('.').pop();
- fileName = fileName.substring(0, fileName.length - extension.length - 1);
- }
- $.ajaxSubmit(
- {
- url: $.createLink('file', 'edit', `fileID=${file.id}`),
- data: {fileName: newName, extension : file.extension},
- load: false,
- onComplete: (res) =>
- {
- if(!res || typeof res !== 'object') return;
- const updatedFile = $.extend({}, file, {title: extension ? `${fileName}.${extension}` : fileName, extension}, res.id ? res : {});
- getDocApp().update('doc', $.extend({}, doc, {files: doc.files.map(f => f.id === file.id ? updatedFile : f)}));
- }
- });
- });
- }
- async function importContentToEditor(type)
- {
- const docApp = getDocApp();
- if(!docApp) return;
- const editor = docApp.editor.$;
- if(!editor) return;
- let content = '';
- if(navigator.clipboard) content = await navigator.clipboard.readText();
- content = await zui.Modal.prompt({size: 'lg', message: `Import ${type}`, defaultValue: content, placeholder: 'Paste content here...', multiline: true});
- return getDocApp().importDoc(content, type);
- }
- /* Import markdown or json file to editor. */
- function importFileToEditor(type, options)
- {
- if(options && options.fromText) return importContentToEditor(type);
- const accept = type === 'markdown' ? '.md' : (type === 'confluence' ? '.html,.txt' : '.json');
- return zui.selectFile(accept).then(file => {
- if(!file) return;
- zui.readFile(file).then(content => {
- if(typeof content !== 'string' || !content.length) return;
- return getDocApp().importDoc(content, type, file.name.split('.').shift());
- });
- });
- }
- function isOpenVersion(version) {
- return /^\d/.test(version || $('#zuiCSS').attr('href').split('?v=').pop());
- }
- /**
- * 定义文档各个试图和 UI 元素的上的操作方法。
- * Define the operation methods on the views and UI elements of the doc.
- */
- const actionsMap =
- {
- /**
- * 定义首页的操作按钮。
- * Define the actions on the home page.
- *
- * @returns {array}
- */
- home: function()
- {
- return [
- hasPriv('createSpace') ? {icon: 'plus', btnType: 'primary', text: getLang('createSpace'), command: 'createSpace'} : null,
- ];
- },
- /**
- * 定义空间的操作按钮。
- * Define the actions of space.
- */
- space: function(info)
- {
- const lang = getLang();
- const items = [];
- const space = info.data; // Space info object.
- /* 获取侧边栏没有文档库时的操作按钮。 Get actions when sidebar no lib. */
- if(info.ui === 'sidebar-no-lib')
- {
- if(!canModifySpace(space) || !hasPriv('createLib')) return null;
- return [{icon: 'plus', text: lang.createLib, command: 'createLib', btnType: 'primary-pale'}];
- }
- if(hasPriv('editSpace')) items.push({text: lang.actions.editSpace, command: `editSpace/${space.id}`});
- if(hasPriv('deleteSpace')) items.push({text: lang.actions.deleteSpace, command: `deleteSpace/${space.id}`});
- if(!items.length) return;
- return [
- {type: 'dropdown', icon: 'cog-outline', square: true, caret: false, placement: info.ui === 'space-card' ? 'bottom-end' : 'top-end', items: items},
- ];
- },
- /**
- * 定义文档的操作按钮。
- * Define the actions of doc.
- */
- doc: function(info)
- {
- const lang = getLang();
- const doc = info.data;
- const canModify = canModifySpace();
- const isApi = isApiDoc(doc);
- const isTemplate = doc.templateType !== '';
- const canEditDoc = canModify && hasPriv(isApi ? 'editApi' : 'edit');
- const isChapter = doc.type === 'chapter';
- /* 侧边栏上的文档操作按钮。Doc actions in sidebar. */
- if(info.ui === 'sidebar')
- {
- if(!canModify) return [];
- const moreItems =
- [
- hasPriv('addChapter') ? {icon: 'plus', text: lang.addSubChapter, command: `addChapter/${doc.id}`} : null,
- hasPriv('addChapter') && doc.parent != 0 ? {icon: 'plus', text: lang.addSameChapter, command: `addChapter/${doc.parent}`} : null,
- !isTemplate && hasPriv('create') ? {icon: 'plus', text: lang.addSubDoc, command: `startCreateDoc/${doc.id}`} : null,
- !isChapter && canMoveDoc(doc) ? {icon: 'folder-move', text: lang.moveDoc, command: `moveDoc/${doc.id}`} : null,
- !doc.frozen && !isChapter && hasPriv('delete') ? {icon: 'trash', text: lang.delete, command: `deleteDoc/${doc.id}`} : null,
- isChapter && hasPriv('editChapter') ? {icon: 'pencil', text: lang.editChapter, command: `editChapter/${doc.id}`} : null,
- isChapter && hasPriv('deleteChapter') ? {icon: 'trash', text: lang.deleteChapter, command: `deleteDoc/${doc.id}`} : null,
- ];
- return [
- (!isChapter && hasPriv('sortDoc')) || (isChapter && hasPriv('sortChapter')) ? {icon: 'move cursor-move', className: 'sort-handler', hint: lang.sortDoc, size: 'xs'} : null,
- moreItems.every(item => item === null) ? null : {icon: 'ellipsis-v', caret: false, placement: 'bottom-end', size: 'xs', items: moreItems},
- ];
- }
- const moreItems = [];
- if(canModify && canMoveDoc(doc)) moreItems.push({icon: 'folder-move', text: lang.moveDoc, command: `moveDoc/${doc.id}`});
- if(!doc.frozen && canModify && hasPriv('delete')) moreItems.push({icon: 'trash', text: lang.delete, command: `deleteDoc/${doc.id}`});
- if(!isApi && canModify && hasPriv('effort')) moreItems.push({icon: 'time', text: lang.effort, command: `effortDoc/${doc.id}`});
- if(!isApi && !isTemplate)
- {
- const canExportWord = hasPriv('exportDoc');
- if(canExportWord && (doc.contentType === 'doc' || doc.contentType === 'markdown'))
- {
- const exportItems = [
- {text: lang.exportWord, command: 'exportWord'},
- config.debug > 5 ? {text: lang.exportPdf, command: 'exportDoc/pdf'} : null,
- config.debug > 5 ? {text: lang.exportImage, command: 'exportDoc/png'} : null,
- {text: lang.exportMarkdown, command: 'exportDoc/markdown'},
- {text: lang.exportHtml, command: 'exportDoc/html'},
- {text: lang.exportJSON, command: 'exportDoc/json'},
- ].filter(Boolean);
- moreItems.push({icon: 'export', text: lang.export, items: exportItems});
- }
- else if(canExportWord)
- {
- moreItems.push({icon: 'export', text: lang.export, command: 'exportWord'});
- }
- }
- if (isApi) {
- const canExportApi = hasPriv('exportApi');
- if (canExportApi) {
- moreItems.push({icon: 'export', text: lang.export, command: 'exportApi'});
- }
- }
- const docApp = this;
- const isOpen = isOpenVersion(config.version);
- if(!isOpen && docApp && docApp.mode === 'view' && doc.status != 'draft' && !doc.api && !isTemplate)
- {
- moreItems.push({icon: 'link', text: getLang('relateObject'), className: 'relateObject-btn', command: 'toggleViewSideTab/relateObject'})
- }
- const isToolbar = info.ui === 'toolbar';
- const isInModal = $(this.element).closest('.modal').length;
- let aiAction = null;
- let aiTeammateAction = null;
- const docAIPrompts = window.docAIPrompts;
- if(!isApi && docAIPrompts && docAIPrompts.length)
- {
- const aiLang = window.docAIPromptLang;
- const aiActionItems = docAIPrompts.map(prompt => ({icon: 'magic', text: prompt.status !== 'active' ? zui.jsx`${prompt.name}<span class="label size-sm gray-500-pale ring-gray-500 whitespace-nowrap ml-1">${aiLang.statuses[prompt.status]}</span>` : prompt.name, command: `executeAIPrompt/${prompt.id}/${doc.id}`, hint: prompt.desc}));
- if(aiActionItems.length === 1) aiAction = aiActionItems[0];
- else aiAction = {icon: 'lightning', text: aiLang.dropdownTitle || 'AI', type: 'dropdown', btnType: 'ai-styled', size: 'sm', caret: 'down', placement: 'bottom-end', items: aiActionItems};
- const aiTeammateLang = window.docAITeammateLang;
- const aiTeammates = window.docAITeammates;
- if(aiTeammates.length)
- {
- const aiTeammateItems = aiTeammates.map(teammate => {
- const name = aiTeammateLang.nameLabel.replace('%s', teammate.name);
- return {text: zui.jsx`<img src="${teammate.avatar}" class="avatar rounded-full mr-2" style="width: 20px; height: 20px; line-height: 20px;" /> ${name}`, hint: name, command: `assignAITeammate/${teammate.id}/${doc.id}`,};
- });
- aiTeammateAction = {icon: 'hand-right', text: aiTeammateLang.dropdownTitle, type: 'dropdown', btnType: 'ai-styled', size: 'sm', caret: 'down', placement: 'bottom-end', items: aiTeammateItems};
- }
- }
- const actions = isInModal ? [] : [
- aiAction,
- aiTeammateAction,
- !isApi && canViewAITask ? {hint: lang.aiTask, icon: 'task-list', command: `viewAITasks/${doc.id}`} : null,
- isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
- canEditDoc ? {icon: 'edit', class: doc.editable ? null : 'disabled', type: doc.editable ? 'ghost text-primary' : 'ghost text-gray', hint: doc.editable ? lang.edit : lang.needEditable, rounded: 'lg', command: doc.editable ? 'startEditDoc' : null} : null,
- (isToolbar && docApp.props.showDocOutline !== false) ? {hint: lang.docOutline, icon: 'list-box', command: 'toggleViewSideTab/outline'} : null,
- (isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'file-log', command: 'toggleViewSideTab/history'} : null,
- moreItems.length ? {icon: 'icon-ellipsis-v', type: 'dropdown', rounded: 'lg', placement: 'bottom-end', caret: false, items: moreItems} : null,
- ];
- return actions;
- },
- /**
- * 定义文档库的操作按钮。
- * Define the actions of modules.
- */
- lib: function(info)
- {
- const docApp = getDocApp();
- const lang = getLang();
- const items = [];
- const lib = info.data;
- const canModify = canModifySpace() || docApp === null;
- const canAddModule = canModify && hasPriv('addModule');
- /* 获取侧边栏没有模块时的操作按钮。 Get actions when sidebar no module. */
- if(info.ui === 'sidebar-no-module')
- {
- if(!canAddModule) return;
- return [{text: lang.actions.addModule, command: `addModule/${lib.id}/0/${lib.id}/child`, icon: 'plus', type: 'primary-pale'}];
- }
- if(canAddModule && info.ui !== 'space-card' && info.ui !== 'sidebar') items.push({text: lang.actions.addModule, command: `addModule/${lib.id}/0/${lib.id}/child`});
- if(canModify && hasPriv('editLib')) items.push({text: lang.actions.editLib, command: `editLib/${lib.id}`});
- if(canModify && lib.type !== 'api' && hasPriv('moveLib') && info.ui !== 'space-card' && info.ui !== 'sidebar-toolbar') items.push({text: lang.moveTo, command: `moveLib/${lib.id}`});
- if(canModify && hasPriv('deleteLib')) items.push({text: lang.actions.deleteLib, command: `deleteLib/${lib.id}`});
- if(!items.length) return;
- if(info.ui === 'sidebar')
- {
- return [
- hasPriv('sortDoclib') ? {icon: 'move cursor-move', className: 'sort-handler', hint: lang.sortDoclib, size: 'xs'} : null,
- items.length ? {icon: 'ellipsis-v', caret: false, placement: 'bottom-end', size: 'xs', items: items} : null,
- ];
- }
- return [
- {type: 'dropdown', icon: info.ui === 'space-card' ? 'ellipsis-v' : 'cog-outline', square: true, caret: false, placement: info.ui === 'space-card' ? 'bottom-end' : 'top-end', items: items},
- ];
- },
- /**
- * 定义目录的操作按钮。
- * Define the actions on the lib page.
- */
- module: function(info)
- {
- const lang = getLang();
- const items = [];
- const module = info.data;
- if(hasPriv('addModule')) items.push({text: lang.actions.addSameModule, command: `addModule/${module.lib}/${module.parent || module.lib}/${module.id}/same`}, {text: lang.actions.addSubModule, command: `addModule/${module.lib}/${module.id}/${module.id}/child`});
- if(hasPriv('editModule')) items.push({text: lang.actions.editModule, command: `editModule/${module.id}`});
- if(hasPriv('deleteModule')) items.push({text: lang.actions.delModule, command: `deleteModule/${module.id}`});
- if(info.ui === 'sidebar')
- {
- return [
- hasPriv('sortModule') ? {icon: 'move cursor-move', className: 'sort-handler', hint: lang.sortLib, size: 'xs'} : null,
- items.length ? {icon: 'ellipsis-v', caret: false, placement: 'bottom-end', size: 'xs', items: items} : null,
- ];
- }
- return items;
- },
- /**
- * 定义文档表格操作栏的操作按钮。
- * Define the actions on the doc table footer.
- */
- 'doc-table': function(info)
- {
- const docApp = this;
- return [hasPriv('batchMoveDoc') ? {
- text: getLang('batchMove'),
- onClick: function()
- {
- /* Get all selected doc id list. */
- const selections = info.dtable.getChecks();
- if(!selections.length) return;
- const docIdList = window.btoa(JSON.stringify(selections));
- const spaceType = docApp.spaceType;
- const spaceID = docApp.spaceID;
- const libID = docApp.libID;
- const moduleID = docApp.moduleID;
- const url = $.createLink('doc', 'batchMoveDoc', 'type=' + spaceType + '&docIdList=' + docIdList + '&spaceID=' + spaceID + '&libID=' + libID + '&moduleID=' + moduleID);
- zui.Modal.open({size: 'sm', url: url});
- }
- } : null];
- },
- /**
- * 定义文档列表的操作按钮。
- * Define the actions on the doc list.
- */
- 'doc-list': function(info)
- {
- const docApp = this;
- const lang = getLang();
- const canModify = canModifySpace();
- const libID = docApp.libID;
- const docID = docApp.docID;
- if(isApiLib(docApp.lib))
- {
- if(!canModify) return;
- const canCreateApi = hasPriv('createApi');
- const command = 'startCreateDoc/' + docID + '/api';
- if(info.ui === 'doc-list-empty')
- {
- return canCreateApi ? [{icon: 'plus', text: lang.createApi, btnType: 'primary', command}] : null;
- }
- const canCreateLib = hasPriv('createLib');
- const items =
- [
- canCreateApi ? {icon: 'plus', text: lang.createApi, command} : null,
- (canCreateApi && canCreateLib) ? {type: 'divider'} : null,
- canCreateLib ? {icon: 'wiki-lib', text: lang.createLib, command: 'createLib'} : null,
- ].filter(Boolean);
- const canExportApi = hasPriv('exportApi') && libID;
- return [
- canExportApi ? {type: 'divider', style: {margin: '6px 0'}} : null,
- canExportApi ? {icon: 'export', text: lang.export, command: 'exportApi'} : null,
- items.length ? {icon: 'plus', type: 'dropdown', btnType: 'primary', size: 'md', text: lang.create, items: items} : null,
- ];
- }
- const canCreateDoc = canModify && hasPriv('create');
- const canCreateLib = canModify && hasPriv('createLib');
- const canCreateSpace = canModify && hasPriv('createSpace');
- const canCreateOffice = canModify && hasPriv('createOffice');
- const canUploadDoc = canModify && hasPriv('uploadFile');
- const canExportDoc = hasPriv('exportDoc') && docApp.spaceType !== 'quick';
- /* 文档列表没有文档时的按钮。Actions for empty doc list. */
- if(info.ui === 'doc-list-empty')
- {
- return canCreateDoc ? [{icon: 'plus', text: lang.createDoc, btnType: 'primary', command: `startCreateDoc/${docID}`}] : null;
- }
- const items = canModify ?
- [
- canCreateDoc ? {icon: 'plus', text: lang.createDoc, command: `startCreateDoc/${docID}`} : null,
- canUploadDoc ? {icon: 'import', text: lang.uploadDoc, command: 'uploadDoc'} : null,
- canCreateDoc ? {type: 'divider'} : null,
- canCreateOffice ? {icon: 'file-word', text: lang.createList.word, command: 'startCreateOffice/word'} : null,
- canCreateOffice ? {icon: 'file-powerpoint', text: lang.createList.ppt, command: 'startCreateOffice/ppt'} : null,
- canCreateOffice ? {icon: 'file-excel', text: lang.createList.excel, command: 'startCreateOffice/excel'} : null,
- (canCreateOffice && (canCreateLib || canCreateSpace)) ? {type: 'divider'} : null,
- canCreateSpace ? {icon: 'cube', text: lang.createSpace, command: 'createSpace'} : null,
- canCreateLib ? {icon: 'wiki-lib', text: lang.createLib, command: 'createLib'} : null,
- ].filter(Boolean) : [];
- return [
- ((canExportDoc && libID > 0) || canCreateDoc) ? {type: 'divider', style: {margin: '6px 0'}} : null,
- canExportDoc && libID > 0 ? {icon: 'export', text: lang.export, command: 'exportWord'} : null, // 不在库中,无法导出
- items.length ? {icon: 'plus', type: 'dropdown', btnType: 'primary', size: 'md', text: lang.create, items: items} : null,
- ];
- },
- /**
- * 定义文档编辑时的操作按钮。
- * Define the actions on toolbar of the doc editing page.
- */
- 'doc-edit': function(info)
- {
- const doc = info.data;
- if(!doc) return;
- const lang = getLang();
- if(isApiLib())
- {
- return [
- {text: lang.save, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveApiDoc'},
- {text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelEditDoc'},
- ];
- }
- const moreItems = [];
- if(!enableHocuspocus && (doc.contentType === 'doc' || doc.contentType === 'markdown') && !isApiDoc(doc))
- {
- if(config.debug > 5) moreItems.push({text: lang.importConfluence, command: 'importFile/confluence'});
- moreItems.push(
- {text: lang.importMarkdown, command: 'importFile/markdown'},
- {text: lang.importJSON, command: 'importFile/json'},
- {type: 'divider'},
- {text: lang.exportJSON, command: 'exportDoc/json'},
- );
- }
- const isToolbar = info.ui === 'toolbar';
- const docApp = this;
- return [
- isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
- (isToolbar && docApp.props.showDocOutline !== false) ? {hint: lang.docOutline, icon: 'list-box', command: 'toggleViewSideTab/outline'} : null,
- (isToolbar && docApp.props.showDocHistory !== false) ? {hint: lang.history, icon: 'file-log', command: 'toggleViewSideTab/history'} : null,
- doc.status === 'draft' ? {text: lang.saveDraft, size: 'md', className: 'btn-wide', type: 'secondary', command: 'saveDoc/draft'} : null,
- {text: lang.release, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveDoc'},
- {text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelEditDoc'},
- {text: lang.settings, size: 'md', type: 'ghost', command: `showDocSettingModal/${doc.id}/${doc.contentType}/1`, icon: 'cog-outline'},
- moreItems.length ? {icon: 'icon-ellipsis-v', type: 'dropdown', rounded: 'lg', placement: 'bottom-end', caret: false, items: moreItems} : null,
- ].filter(Boolean);
- },
- /**
- * 定义文档创建时的操作按钮。
- * Define the actions on toolbar of the doc creating page.
- */
- 'doc-create': function(info)
- {
- const lang = getLang();
- if(isApiLib())
- {
- return [
- {text: lang.save, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveApiDoc'},
- {text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelCreateDoc'},
- ];
- }
- const moreItems = [];
- const creatingDoc = this.signals.creatingDoc.value;
- if(creatingDoc && creatingDoc.contentType === 'doc')
- {
- moreItems.push(
- {text: lang.importMarkdown, command: 'importFile/markdown'},
- {text: lang.importJSON, command: 'importFile/json'},
- {type: 'divider'},
- {text: lang.exportJSON, command: 'exportDoc/json'},
- );
- }
- const isToolbar = info.ui === 'toolbar';
- const docApp = this;
- return [
- isToolbar ? {hint: docApp.fullscreen ? lang.exitFullscreen : lang.enterFullscreen, icon: docApp.fullscreen ? 'fullscreen-exit' : 'fullscreen', command: 'toggleFullscreen'} : null,
- (isToolbar && docApp.props.showDocOutline !== false) ? {hint: lang.docOutline, icon: 'list-box', command: 'toggleViewSideTab/outline'} : null,
- {text: lang.saveDraft, size: 'md', className: 'btn-wide', type: 'secondary', command: 'saveNewDoc/draft'},
- {text: lang.release, size: 'md', className: 'btn-wide', type: 'primary', command: 'saveNewDoc'},
- {text: lang.cancel, size: 'md', className: 'btn-wide', type: 'primary-outline', command: 'cancelCreateDoc'},
- moreItems.length ? {icon: 'icon-ellipsis-v', type: 'dropdown', rounded: 'lg', placement: 'bottom-end', caret: false, items: moreItems} : null,
- ];
- },
- /**
- * 定义文件的操作按钮。
- * Define the actions of file.
- */
- file: function(info)
- {
- const doc = info.doc;
- const file = info.data;
- const docApp = getDocApp();
- const isReadonly = docApp.mode === 'view';
- const privs = docApp.props.privs;
- const lang = getLang();
- const canEdit = !isReadonly && privs.edit && (!doc.privs || doc.privs.edit !== false) && privs.editFile;
- const canDelete = !isReadonly && privs.edit && (!doc.privs || doc.privs.edit !== false) && privs.deleteFile;
- const canDownload = privs.downloadFile;
- let previewAction = null;
- let isOfficeFile = 'doc|docx|xls|xlsx|ppt|pptx|pdf'.includes(file.extension);
- let canPreview = privs.previewFile && 'txt|jpg|jpeg|gif|png|bmp|mp4'.includes(file.extension);
- if(privs.previewFile && typeof libreOfficeTurnon !== 'undefined' && libreOfficeTurnon && isOfficeFile) canPreview = true;
- if(canPreview)
- {
- previewAction = {url: $.createLink('file', 'download', `fileID=${file.id}&mouse=left`), hint: lang.filePreview, icon: 'eye', target: '_blank'};
- if(!isOfficeFile)
- {
- previewAction['data-toggle'] = 'modal';
- previewAction['data-size'] = 'lg';
- delete previewAction.target;
- }
- }
- return [
- previewAction,
- canDownload ? {target: '_blank', url: zui.formatString(docApp.props.fileUrl, file), hint: lang.fileDownload, icon: 'download'} : null,
- canEdit ? {hint: lang.fileRename, icon: 'pencil-alt', onClick: renameDocFile.bind(this, file, doc)} : null,
- canDelete ? {hint: lang.fileDelete, icon: 'trash', onClick: deleteDocFile.bind(this, file, doc)} : null,
- ].filter(Boolean);
- },
- 'file-list': function(info)
- {
- return [hasPriv('exportFiles') ? {icon: 'export', text: getLang('export'), command: 'exportFiles'} : null];
- }
- };
- function getActions(type, info)
- {
- const builder = actionsMap[type];
- if(builder) return builder.call(this, info);
- }
- /**
- * 定义界面操作命令。文档中的大部分操作按钮都会调用这里定义的命令。
- * Define the UI commands. Most of the action buttons in the doc will call the commands defined here.
- */
- const commands =
- {
- /* 创建文档。 Create doc. */
- startCreateDoc: function(_, args)
- {
- const docApp = getDocApp();
- if(!docApp.libList.length) return zui.Modal.alert(getLang('createLibFirst'));
- const docType = (args && args[1]) || 'doc';
- const {spaceType} = docApp;
- if(spaceType === 'api' || docType === 'api') return docApp.startCreateDoc();
- const templateID = args?.[1] ?? 0;
- const {spaceID, libID, moduleID} = docApp;
- return showDocBasicModal(args?.[0] ?? 0, 0, true, docType).then((formData) => {
- zui.Editor.loadModule().then(() => {
- const emptyDoc = zui.Editor.createEmptyDoc();
- const snapshot = zui.Editor.toSnapshot(emptyDoc);
- const doc = {contentType: 'doc', status: 'draft', content: JSON.stringify(snapshot), template: templateID};
- return submitNewDoc(doc, spaceID, libID, moduleID, formData, (newDoc) => {
- docApp.selectDoc(newDoc.id);
- docApp.startEditDoc(newDoc.id);
- });
- });
- });
- },
- startEditDoc: function(_, [doc], options)
- {
- const docApp = getDocApp();
- doc = doc || docApp._doc.value?.data;
- if (typeof doc !== 'object') {
- doc = docApp._treeMap.value.docs.get(doc)?.data;
- }
- if(doc.frozen) return zui.Modal.alert(getLang('frozenTips').replace('%s', getLang('edit')));
- /** 如果是附件类型并且没有内容的文档,则跳转到上传文档页面进行编辑。 */
- if(doc.type === 'attachment' && !doc.hasContent) {
- const type = docApp.lib ? docApp.lib.data.type : docApp.spaceType;
- const url = $.createLink('doc', 'uploadDocs', `docID=${doc.id}&objectType=${type}&objectID=${docApp.spaceID}&libID=${doc.lib}&moduleID=${doc.module}&type=attachment`);
- zui.Modal.open({url: url});
- return false;
- }
- return docApp.startEditDoc(doc, options);
- },
- /** 上传文档。Upload Doc. */
- uploadDoc: function(_, args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID
- const type = docApp.lib ? docApp.lib.data.type : docApp.spaceType;
- const url = $.createLink('doc', 'uploadDocs', `docID=${docID}&objectType=${type}&objectID=${docApp.spaceID}&libID=${docApp.libID}&moduleID=${docApp.moduleID}&type=attachment`);
- zui.Modal.open({url: url});
- },
- /** 创建 Office 文件。 Start create office file. */
- startCreateOffice: function(_, args)
- {
- const type = args[0];
- const docApp = getDocApp();
- const url = $.createLink('doc', 'create', `objectType=${docApp.spaceType}&objectID=${docApp.spaceID}&libID=${docApp.libID}&moduleID=${docApp.moduleID}&type=${type}`);
- zui.Modal.open({url: url});
- },
- createSpace: function()
- {
- const docApp = getDocApp();
- const params = docApp.spaceType == 'mine' ? 'type=mine' : '';
- const url = $.createLink('doc', 'createSpace', params);
- zui.Modal.open({size: 'sm', url: url});
- },
- editSpace: function(_, args)
- {
- const docApp = getDocApp();
- const spaceID = args[0] || docApp.spaceID;
- const url = $.createLink('doc', 'editSpace', `libID=${spaceID}`);
- zui.Modal.open({size: 'sm', url: url});
- },
- deleteSpace: function(_, args)
- {
- const docApp = getDocApp();
- const spaceID = args[0] || docApp.spaceID;
- $.ajaxSubmit(
- {
- confirm: getLang('confirmDeleteSpace'),
- url: $.createLink('doc', 'deleteSpace', `libID=${spaceID}`),
- load: false,
- onSuccess: function(res)
- {
- if(res && res.result === 'success')
- {
- const docApp = getDocApp();
- if(spaceID === docApp.spaceID && docApp.mode !== 'home')
- {
- const spaceList = docApp.spaceList.filter(x => x.id !== spaceID);
- if(spaceList.length)
- {
- docApp.selectSpace(spaceList[0].id);
- return;
- }
- docApp.switchView({spaceID: 0, libID: 0, moduleID: 0, docID: 0}, 'home');
- }
- docApp.delete('space', spaceID);
- }
- }
- });
- },
- createLib: function(_, args)
- {
- const docApp = getDocApp();
- const spaceID = args[0] || docApp.spaceID;
- const url = $.createLink('doc', 'createLib', spaceID ? `type=${docApp.spaceType}&objectID=${spaceID}` : `type=${docApp.spaceType}`);
- zui.Modal.open({size: 'sm', url: url});
- },
- moveLib: function(_, args)
- {
- const docApp = getDocApp();
- const libID = args[0] || docApp.libID;
- const url = $.createLink('doc', 'moveLib', `libID=${libID}`);
- zui.Modal.open({size: 'sm', url: url});
- },
- editLib: function(_, args)
- {
- const docApp = getDocApp();
- const libID = args[0] || docApp.libID;
- const url = $.createLink(isApiLib(libID) ? 'api' : 'doc', 'editLib', `libID=${libID}`);
- zui.Modal.open({size: 'sm', url: url});
- },
- deleteLib: function(_, args)
- {
- const docApp = getDocApp();
- const libID = args[0] || docApp.libID;
- $.ajaxSubmit(
- {
- confirm: getLang('confirmDeleteLib'),
- url: $.createLink('doc', 'deleteLib', `libID=${libID}`),
- load: false,
- onSuccess: function()
- {
- const docApp = getDocApp();
- docApp.delete('lib', libID);
- if(docApp.mode === 'home') docApp.loadHomeLibs();
- }
- });
- },
- addModule: function(_, args)
- {
- zui.Modal.prompt({message: getLang('moduleName')}).then(newMoudleName =>
- {
- if(!newMoudleName) return;
- const docApp = getDocApp();
- const libID = args[0] || docApp.libID;
- const parentID = args[1] || 0;
- const objectID = args[2] || 0;
- const createType = args[3] || 'child';
- const data =
- {
- name: newMoudleName,
- libID: libID,
- parentID: parentID,
- objectID: objectID,
- moduleType: isApiLib(libID) ? 'api' : 'doc',
- isUpdate: false,
- createType: createType,
- };
- $.ajaxSubmit(
- {
- load: false,
- url: $.createLink('tree', 'ajaxCreateModule'),
- data: data,
- onSuccess: (res) =>
- {
- if(!res.module) return;
- const docApp = getDocApp();
- docApp.update('module', res.module);
- if(!docApp.hasEditingDoc) docApp.selectModule(res.module.id);
- }
- })
- });
- },
- editModule: function(_, args)
- {
- const docApp = getDocApp();
- const moduleID = args[0] || docApp.moduleID;
- const url = $.createLink('doc', 'editCatalog', `moduleID=${moduleID}&type=doc`);
- zui.Modal.open({size: 'sm', url: url});
- },
- deleteModule: function(_, args)
- {
- const docApp = getDocApp();
- const moduleID = args[0] || docApp.moduleID;
- const moduleInfo = docApp.treeMap.modules.get(+moduleID);
- $.ajaxSubmit(
- {
- confirm: getLang(moduleInfo.modules.length > 0 || moduleInfo.docs.length > 0 ? 'confirmDeleteModuleWithSub' : 'confirmDeleteModule'),
- url: $.createLink('doc', 'deleteCatalog', `moduleID=${moduleID}`),
- load: false,
- onSuccess: function(res)
- {
- if(!res) return;
- if(res.result === 'success')
- {
- const docApp = getDocApp();
- const moduleInfo = docApp.treeMap.modules.get(+moduleID);
- if(moduleInfo)
- {
- const parent = moduleInfo.parent;
- docApp.changeState(
- {
- libID: parent.type === 'lib' ? parent.data.id : docApp.libID,
- module: parent.type === 'lib' ? 0 : parent.data.id,
- })
- }
- else if(docApp.mode === 'list')
- {
- docApp.selectLib(docApp.libID, 0);
- }
- docApp.delete('module', moduleID);
- }
- else if(res.message)
- {
- zui.Modal.alert(res.message);
- }
- }
- });
- },
- collectDoc: function(_, args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID;
- $.post($.createLink('doc', 'collect', `objectID=${docID}&objectType=doc`), {}, function(res)
- {
- if(typeof res == 'string') res = JSON.parse(res);
- if(!checkResponse(res)) return;
- const collected = res.status === 'yes';
- const doc = docApp.getDoc(docID);
- getDocApp().update('doc', $.extend(doc, {isCollector: collected, collects: collected ? doc.collects + 1 : doc.collects - 1}));
- });
- },
- addChapter: function(_, args)
- {
- const docApp = getDocApp();
- const {spaceID, libID, moduleID} = docApp;
- return showDocBasicModal(args[0], 0, false, 'chapter').then((formData) => {
- const doc = {type: 'chapter', status: 'normal', parent: args[0]};
- return submitNewDoc(doc, spaceID, libID, moduleID, formData).then(() => {
- docApp.load(null, null, null, {noLoading: false, picks: 'doc'});
- if(docBasicModal.current)
- {
- docBasicModal.current.destroy();
- docBasicModal = {};
- }
- });
- });
- },
- editChapter: function(_, args)
- {
- const docApp = getDocApp();
- const {spaceID, libID, moduleID} = docApp;
- return showDocBasicModal(0, args[0], false, 'chapter').then((formData) => {
- return submitEditDoc({id: args[0]}, formData);
- });
- },
- moveDoc: function(_, args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID;
- const libID = docApp.libID;
- const spaceType = docApp.spaceType;
- const spaceID = docApp.spaceID;
- const url = $.createLink('doc', 'moveDoc', `docID=${docID}&libID=${libID}&spaceType=${spaceType}&space=${spaceID}`);
- zui.Modal.open({size: 'sm', url: url});
- },
- handleMovedDoc(_, args)
- {
- const docID = +args[0];
- const space = args[1];
- const spaceID = +(space.includes('.') ? space.split('.').pop() : space);
- const docApp = getDocApp();
- if(docApp.mode === 'view')
- {
- if(spaceID === docApp.spaceID) docApp.loadDoc(docID).then(() => docApp.selectDoc(docID));
- else if(space.startsWith(docApp.spaceType)) docApp.loadDoc(docID).then(() => docApp.selectLib(docApp.libID));
- else loadPage($.createLink('doc', 'view', `docID=${docID}`));
- }
- else
- {
- docApp.load(null, null, null, {noLoading: true, picks: 'doc'});
- }
- },
- startConvertDoc: function(_, args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID;
- const lang = getLang();
- zui.Modal.confirm({title: lang.convertToNewDoc, content: lang.convertToNewDocConfirm}).then(result =>
- {
- if(!result) return;
- docApp.startEditDoc(docID, {convert: true});
- });
- },
- deleteDoc: function(_, args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID;
- const isApi = isApiDoc(docID);
- const docInfo = docApp.treeMap.docs.get(docID)
- const doc = docInfo.data;
- const isChapter = doc?.type === 'chapter';
- $.ajaxSubmit(
- {
- confirm: getLang(isChapter ? (docInfo.docs.length > 0 ? 'confirmDeleteChapterWithSub' : 'confirmDeleteChapter') : (docInfo.docs.length > 0 ? 'confirmDeleteWithSub' : 'confirmDelete')),
- url: $.createLink(isApi ? 'api' : 'doc', 'delete', `${isApi ? 'apiID' : 'docID'}=${isApi ? getApiID(docID) : docID}`),
- load: false,
- onSuccess: function()
- {
- getDocApp().delete('doc', docID);
- }
- });
- },
- effortDoc: function(_,args)
- {
- const docApp = getDocApp();
- const docID = args[0] || docApp.docID;
- const url = $.createLink('effort', 'createForObject', `objectType=doc&objectID=${docID}`);
- zui.Modal.open({url: url, size: 'sm'});
- },
- exportWord: function(_, args)
- {
- const docApp = getDocApp();
- const type = docApp.spaceType;
- const libID = args[0] || docApp.libID;
- const moduleID = args[1] || docApp.moduleID;
- const docID = args[2] || docApp.docID;
- const url = $.createLink('doc', `${type}2export`, `libID=${libID}&moduleID=${moduleID}&docID=${docID}&objectID=${docApp.spaceID}`);
- if(docID)
- {
- window.open(url, '_self');
- return;
- }
- zui.Modal.open({url: url, size: 'sm'});
- },
- exportApi: function(_, args)
- {
- const docApp = getDocApp();
- const libID = args[0] || docApp.libID;
- const release = args[1] || docApp.signals.libReleaseMap.value[libID] || 0;
- const moduleID = args[2] || docApp.moduleID;
- let docID = args[3] || docApp.docID;
- if(typeof docID === 'string') docID = getApiID(docID);
- const url = $.createLink('api', 'export', `libID=${libID}&version=0&release=${release}&moduleID=${moduleID}${docID ? `&apiID=${docID}` : ''}`);
- if(docID)
- {
- window.open(url, '_self');
- return;
- }
- zui.Modal.open({url: url, size: 'sm'});
- },
- importFile: function(info, args)
- {
- const type = args[0] || 'markdown';
- const docApp = getDocApp();
- const editor = docApp.editor.$;
- const altKey = info.event.altKey;
- if(editor.isEmpty) return importFileToEditor(type, {fromText: altKey});
- zui.Modal.confirm({message: getLang('importConfirm')})
- .then((result) => result && importFileToEditor(type, {fromText: altKey}));
- },
- showDocSettingModal: function(_, args)
- {
- const docApp = getDocApp();
- const doc = docApp.doc;
- const docID = args[0] || doc.id;
- const docType = args[1] || doc.contentType;
- const saveEdited = args[2] || 0;
- showDocBasicModal(0, docID).then(formData => {
- savingDocData[docID] = formData;
- if(saveEdited == 1)
- {
- const docData = {
- content : doc.data.content,
- status : doc.data.status,
- contentType: doc.data.contentType,
- type : doc.data.type,
- lib : doc.data.lib,
- module : doc.data.module,
- title : doc.data.title,
- keywords : doc.data.keywords,
- acl : doc.data.acl,
- space : doc.data.space,
- uid : doc.data.uid,
- };
- mergeDocFormData(docData, formData);
- }
- });
- },
- /**
- * 保存 API 文档数据。
- * Save the API doc data.
- */
- saveApiDoc: function()
- {
- /* 触发 API 表单的提交事件。 */
- $('#docApp .doc-view form').trigger('submit');
- },
- /**
- * 加载指定的 API 文档。
- * Load the specified API doc.
- */
- loadApi: function(_, args)
- {
- const apiID = getApiID(args[0] || this.docID);
- const version = args[1] || 0;
- const release = args[2] || 0;
- const select = !!args[3];
- $.getJSON($.createLink('api', 'ajaxGetApi', `apiID=${apiID}&version=${version}&release=${release}`), function(result)
- {
- if(!result || typeof result !== 'object') return;
- result.id = `api.${apiID}`;
- const docApp = getDocApp();
- docApp.update('doc', result);
- if(select) docApp.selectDoc(result.id);
- });
- },
- /**
- * 选择 API 文档。
- * Select the specified API doc.
- */
- selectApi: function(_, args)
- {
- const apiID = args[0];
- getDocApp().selectDoc(`api.${getApiID(apiID)}`);
- },
- /**
- * 显示结构列表。
- * Show the struct list.
- */
- showStructs: function()
- {
- getDocApp().changeState(
- {
- mode: 'list',
- moduleID: 0,
- docID: 0,
- listType: 'structs',
- });
- },
- /**
- * 显示版本列表。
- * Show the release list.
- */
- showReleases: function()
- {
- getDocApp().changeState(
- {
- mode: 'list',
- moduleID: 0,
- docID: 0,
- listType: 'releases',
- });
- },
- /**
- * 显示API 目录。
- * Show the api catalog.
- */
- showModules: function()
- {
- getDocApp().changeState(
- {
- mode: 'list',
- moduleID: 0,
- docID: 0,
- listType: '',
- });
- },
- /**
- * 获取库的 API 列表。
- * Get the API list of the library.
- */
- loadLibApi: function(_, args)
- {
- const docApp = getDocApp();
- const libReleaseMap = docApp.signals.libReleaseMap.value;
- const libID = args[0] || docApp.libID;
- if(!libID) return;
- const releaseID = args[1] || libReleaseMap[libID] || 0;
- const url = $.createLink('api', 'ajaxGetLibApiList', `libID=${libID}&releaseID=${releaseID}`);
- $.getJSON(url, function(data)
- {
- const lib = docApp.getLib(libID);
- if(lib && lib.docs && lib.docs.length) docApp.delete('doc', lib.docs.map(x => x.data.id));
- data.forEach((x) => x.id = `api.${x.id}`);
- docApp.update('doc', data);
- });
- },
- /**
- * 更改当前库的发布版本。
- * Change the release of the current library.
- */
- changeLibRelease: function(_, args)
- {
- const docApp = getDocApp();
- const libID = args[0];
- const release = args[1];
- const libReleaseMap = docApp.signals.libReleaseMap.value;
- if(libReleaseMap[libID] === release) return;
- libReleaseMap[libID] = release;
- docApp.signals.libReleaseMap.value = $.extend({}, libReleaseMap);
- docApp.executeCommand('loadLibApi', [libID, release]);
- const doc = docApp.doc;
- if(doc && doc.data.lib === libID) docApp.executeCommand('loadApi', [doc.data.id, 0, release]);
- },
- /**
- * 加载懒加载内容。
- * Load the lazy content.
- */
- loadLazyContent: function(_, args)
- {
- const selector = args[0];
- if(!selector) return;
- $(selector).closest('.lazy-content').trigger('loadContent');
- },
- /**
- * 更新懒加载内容。
- * Update the lazy content.
- */
- updateLazyContent: function(context, args)
- {
- const event = context.event;
- const $element = $(event.currentTarget);
- const selector = args[0] || $element.data('lazyTarget');
- const $lazy = (selector ? $(selector) : $element).closest('.lazy-content');
- const url = $element.data('url') || $element.attr('href');
- if(url) $lazy.trigger('loadContent', url);
- event.preventDefault();
- event.stopPropagation();
- },
- /**
- * 执行禅道智能体。
- * Execute the zentao AI prompt.
- */
- executeAIPrompt: function(_, args)
- {
- const promptID = args[0];
- const docID = args[1];
- const url = $.createLink('ai', 'promptExecute', `promptId=${promptID}&objectId=${docID}&auto=0`);
- $.ajaxSubmit({url: url, method: 'POST'});
- },
- /**
- * 批量导出附件库中的附件。
- * Batch export attachments in the attachment library.
- */
- exportFiles: function(_, args)
- {
- const docApp = getDocApp();
- const objectID = docApp.spaceID;
- const objectType = docApp.spaceType;
- const url = $.createLink('doc', 'exportfiles', `objectID=${objectID}&objectType=${objectType}`);
- zui.Modal.open({url: url, size: 'sm'});
- },
- /*
- * 委派数字员工任务。
- * Assign the ai task to the ai teammate.
- */
- assignAITeammate: function(_, args)
- {
- const teammateID = args[0];
- const docID = args[1];
- const pageInfo = 'doc,view';
- loadModal($.createLink('aiteammate', 'assignagent', `teammateID=${teammateID}&objectType=doc&objectID=${docID}&pageInfo=${pageInfo}`), null, {size: 'sm'});
- },
- /**
- * 查看数字员工任务。
- * View the ai tasks.
- */
- viewAITasks: function(_, args)
- {
- const docID = args[0];
- loadModal($.createLink('aitask', 'browse', `teammate=0&browseType=&involved=0&orderBy=id_desc¶m=0&recTotal=0&recPerPage=20&pageID=1&objectType=doc&objectID=${docID}`));
- }
- };
- function getApiID(id)
- {
- if(typeof id === 'number') return id;
- if(String(+id) === id) return +id;
- return +id.replace('api.', '');
- }
- /**
- * 获取列表类型。
- * Get the list type.
- *
- * @param {object} docApp
- * @returns {string}
- */
- function getListType(docApp)
- {
- docApp = docApp || getDocApp();
- if(docApp.mode !== 'list' || docApp.module) return '';
- const listType = docApp.signals.listType.value;
- return listType;
- }
- /**
- * 定义页面上的自定义渲染器。
- * Define the custom renderers on the page.
- */
- const customRenders =
- {
- /**
- * 定义 API 文档编辑器渲染,包括查看、编辑和创建。
- * Define the API doc editor render, including view, edit and create.
- */
- editor: function()
- {
- const mode = this.mode;
- if(!isApiLib())
- {
- const docInfo = this.doc;
- const doc = docInfo ? docInfo.data : null;
- if (mode === 'diff') {
- const {
- diffVersions,
- spaceType,
- } = this.signals;
- const versions = diffVersions ? diffVersions.value : [];
- if (versions.length === 2) {
- return {
- fetcher: $.createLink('doc', 'ajaxDiff', `&objectType=${spaceType.value}&docID=${doc.id}&newVersion=${versions[0]}&oldVersion=${versions[1]}`),
- };
- }
- }
- if(mode === 'view' && !hasPriv('view')) return {html: `<h1>${doc ? doc.title : ''}</h1><p>${getDocAppLang('accessDenied')}</p>`};
- return;
- }
- if(mode === 'create')
- {
- const libID = this.libID;
- const moduleID = this.moduleID;
- return {fetcher: $.createLink('api', 'create', `libID=${libID}&moduleID=${moduleID}&space=api`), loadingText: getDocAppLang('loading')};
- }
- if(mode === 'edit')
- {
- const doc = this.doc.data;
- return {fetcher: $.createLink('api', 'edit', `apiID=${getApiID(doc.id)}`), loadingText: getDocAppLang('loading')};
- }
- const doc = this.doc.data;
- if(!hasPriv('viewApi')) return {html: `<h1>${doc ? doc.title : ''}</h1><p>${getDocAppLang('accessDenied')}</p>`};
- const release = this.signals.libReleaseMap.value[doc.lib] || 0;
- const version = this.signals.docVersion.value || 0;
- return {fetcher: $.createLink('api', 'view', `libID=${doc.lib}&apiID=${getApiID(doc.id)}&moduleID=${doc.module}&version=${version}&release=${release}`), loadingText: getDocAppLang('loadingDocsData'), className: 'doc-editor-content'};
- },
- /**
- * 定义 API 文档列表渲染,包括结构和版本。
- * Define the API doc list render, including structs and releases.
- */
- list: function()
- {
- if(!isApiLib()) return;
- const listType = getListType(this);
- const libID = getApiID(this.libID);
- const releaseID = this.signals.libReleaseMap.value[libID] || 0;
- if(listType === 'structs') return {fetcher: $.createLink('api', 'struct', `libID=${this.libID}&releaseID=${releaseID}`), loadingText: getDocAppLang('loading'), className: 'api-struct-list'};
- if(listType === 'releases') return {fetcher: $.createLink('api', 'releases', `libID=${this.libID}`), loadingText: getDocAppLang('loading'), className: 'api-release-list'};
- },
- /**
- * 定义 API 文档列表筛选菜单渲染,当展示结构和版本时不显示筛选菜单。
- * Define the API doc list filter menu render, not show the filter menu when showing structs and releases.
- */
- filters: function()
- {
- if(!isApiLib(null, this)) return;
- const listType = getListType(this);
- if(this.mode !== 'list' || !listType) return;
- return null;
- },
- /**
- * 定义 API 文档列表工具栏渲染。
- * Define the API doc list toolbar render.
- */
- toolbar: function()
- {
- if(!isApiLib()) return;
- const listType = getListType(this);
- if(this.mode === 'list' && listType)
- {
- const libID = getApiID(this.libID);
- const items = [];
- if(hasPriv('createStruct') && listType === 'structs') items.push({text: getDocAppLang('createStruct'), icon: 'plus', btnType: 'primary', 'data-toggle': 'modal', 'data-size': 'lg', url: $.createLink('api', 'createStruct', `libID=${libID}`)});
- if(hasPriv('createRelease') && listType === 'releases') items.push({text: getDocAppLang('createRelease'), icon: 'plus', btnType: 'primary', 'data-toggle': 'modal', url: $.createLink('api', 'createRelease', `libID=${libID}`)});
- if(!items.length) return null;
- return {component: 'toolbar', props: {items: items}};
- }
- },
- /**
- * 定义顶部面包屑导航渲染。
- * Define the top breadcrumb render.
- */
- 'app-nav': function(items)
- {
- const lib = this.lib;
- if(!lib || !isApiLib(lib)) return items;
- const versions = lib.data.versions;
- if(versions && versions.length)
- {
- const viewIndex = items.findIndex(item => item[0] === 'lib');
- if(viewIndex >= 0)
- {
- const libView = items[viewIndex][1];
- const libID = getApiID(lib.data.id);
- const release = this.signals.libReleaseMap.value[libID] || 0;
- const options = [{text: getDocAppLang('latestVersion'), value: 0, selected: !release, command: `changeLibRelease/${libID}/0`}];
- versions.forEach(version => options.push({selected: release === version.id, text: `v${version.version}`, value: version.id, command: `changeLibRelease/${libID}/${version.id}`}));
- const currentVersion = versions.find(x => x.id === release);
- const versionPicker = zui.renderCustomContent(
- {
- content:
- {
- component: 'DropdownButton',
- props:
- {
- text : currentVersion ? currentVersion.version : getDocAppLang('latestVersion'),
- size : 'xs',
- type : 'gray-pale',
- rounded : 'full',
- className: 'h-4 gap-1 mr-2',
- items : options,
- }
- }
- });
- items[viewIndex] = ['lib', [libView, versionPicker]];
- }
- }
- const listType = getListType(this);
- if(this.mode !== 'list' || !listType) return items;
- if(listType === 'structs') items.push([listType, zui.renderCustomContent({className: 'mx-2', content: getDocAppLang('struct')})]);
- if(listType === 'releases') items.push([listType, zui.renderCustomContent({className: 'mx-2', content: getDocAppLang('releases')})]);
- return items;
- },
- /**
- * 定义侧边栏渲染,显示结构、版本和模块。
- * Define the sidebar render, show structs, releases and modules.
- */
- 'sidebar-before': function()
- {
- if(!isApiLib()) return;
- const canViewStructs = docAppHasPriv('struct');
- const canViewReleases = docAppHasPriv('releases');
- if(!canViewStructs && !canViewReleases) return;
- const isListMode = this.mode === 'list';
- const lang = getDocAppLang();
- const listType = getListType(this);
- const items = [];
- if(canViewStructs) items.push({text: lang.struct, selected: listType === 'structs' && isListMode, icon: 'treemap muted', command: 'showStructs'}, {type: 'divider', className: 'my-1'});
- if(canViewReleases) items.push({text: lang.releases, selected: listType === 'releases' && isListMode, icon: 'version muted', command: 'showReleases'}, {type: 'divider', className: 'my-1'});
- items.push({text: lang.module, icon: 'list muted', command: 'showModules'});
- return {
- component: 'tree',
- className: 'p-2 pb-0 api-lib-menu',
- props: {items: items, itemProps: {className: 'state'}}
- };
- }
- };
- /**
- * 获取文档界面上的表格初始化选项。
- * Get the table initialization options on the doc UI.
- *
- * @param {object} options
- * @param {object} info
- * @returns {object}
- */
- function getTableOptions(options, info)
- {
- const lang = getLang();
- if(info.type === 'doc-list')
- {
- const tableCols = lang.tableCols;
- const canModify = canModifySpace(this.space);
- options.cols.forEach(col =>
- {
- if(typeof tableCols[col.name] === 'string') col.title = tableCols[col.name];
- if(!config.clientLang.includes('zh'))
- {
- if(col.name === 'addedDate' || col.name == 'editedDate') col.width = '120';
- }
- if(col.name === 'actions' && col.actionsMap)
- {
- if(!canModify) col.actions = [];
- col.actions = col.actions.filter(action => hasPriv(action == 'move' ? 'moveDoc' : action));
- const actionHints = {edit: lang.editDoc, move: lang.moveDoc, delete: lang.deleteDoc};
- const privMap = {edit: hasPriv('edit'), move: hasPriv('moveDoc'), delete: hasPriv('delete')};
- $.each(col.actionsMap, (key, value) =>
- {
- if(typeof actionHints[key] === 'string') value.hint = actionHints[key];
- value.disabled = !privMap[key];
- });
- col.actionItemCreator = function(item, info)
- {
- const rowData = info.row.data;
- item.command = item.command.replace('{id}', String(rowData.id));
- if(rowData.frozen && (item.key === 'edit' || item.key === 'trash'))
- {
- const actionHint = item.key == 'trash' ? actionHints['delete'] : actionHints[item.key];
- item.hint = lang.frozenTips.replace('%s', actionHint);
- item.disabled = true;
- }
- return item;
- }
- }
- });
- options.onCheckChange = function(changes)
- {
- const checkedList = this.getChecks();
- $.cookie.set('checkedItem', checkedList, {expires:config.cookieLife, path:config.webRoot});
- }
- }
- if(info.type === 'file-list')
- {
- const tableCols = lang.fileTableCols;
- const canExportFiles = hasPriv('exportFiles');
- options.cols.forEach(col =>
- {
- if(typeof tableCols[col.name] === 'string') col.title = tableCols[col.name];
- if(col.name == 'objectName')
- {
- const onRenderCellBackup = col.onRenderCell;
- col.onRenderCell = function(result, info)
- {
- const file = info.row.data;
- if(file.rawObjectType == 'stepResult')
- {
- const url = $.createLink('testtask', 'results', `runID=0&caseID=${file.objectID}`);
- result[0] = {html: `${file.objectName}<a href="${url}" data-toggle="modal" data-size="lg" title="${file.objectName}#${file.objectID} ${file.sourceName}">#${file.objectID} ${file.sourceName}</a>`};
- return result;
- }
- return onRenderCellBackup.call(this,result,info);
- }
- }
- if(col.name === 'id' && canExportFiles) col.checkbox = true;
- });
- if(canExportFiles)
- {
- options.checkable = true;
- options.onCheckChange = function(changes)
- {
- const checkedList = this.getChecks();
- $.cookie.set('checkedFileItem', checkedList, {expires:config.cookieLife, path:config.webRoot});
- }
- }
- return options;
- }
- if(!hasPriv('batchMoveDoc') && !hasPriv('exportDoc'))
- {
- options.checkable = false;
- options.footer = options.footer.filter(f => f !== 'checkbox' && f !== 'checkedInfo');
- }
- return options;
- }
- /**
- * 获取文档界面上的列表筛选菜单。
- * Get the filter menu on the doc UI.
- *
- * @param {string} mode
- * @returns {[key: string, text: string][]}
- */
- function getFilterTypes(mode)
- {
- if(mode === 'home')
- {
- if(docAppData.currentSpaceType === 'project') return getLang('projectFilterTypes');
- if(docAppData.currentSpaceType === 'product') return getLang('productFilterTypes');
- return getLang('spaceFilterTypes');
- }
- if(mode === 'list')
- {
- const lib = this.lib;
- if(lib && lib.data.type === 'api') return getLang('apifilterTypes');
- return getLang('filterTypes');
- }
- if(mode === 'files') return getLang('fileFilterTypes');
- }
- /**
- * 检查文档是否符合筛选条件。
- * Check if the doc matches the filter condition.
- *
- * @param {string} type
- */
- function isMatchFilter(type, filterType, item)
- {
- if(type === 'doc')
- {
- if(filterType === 'createdByMe') return item.addedBy === docAppData.currentUser;
- if(filterType === 'editedByMe') return item.editedBy === docAppData.currentUser;
- if(filterType === 'draft') return item.status === 'draft';
- if(filterType === 'collect') return item.isCollector;
- if(filterType === 'released') return item.status === 'normal';
- }
- if(type === 'project' || type === 'product')
- {
- return filterType !== 'mine' || item.isMine;
- }
- return true;
- }
- /**
- * 将 [key, ...] 形式的顺序列表转换为 {key: order, ...} 形式。
- * Convert the order list in the form of [key, ...] to {key: order, ...}.
- *
- * @param {number[]} orders
- * @returns {object}
- */
- function formatOrders(orders, useIndex)
- {
- const orderedKeys = useIndex ? [] : Array.from(orders).sort((a, b) => a - b);
- return orders.reduce((map, key, index) =>
- {
- map[key] = useIndex ? index : orderedKeys[index];
- return map;
- }, {});
- }
- /**
- * 对文档条目进行排序。
- * Sort the doc items.
- *
- * @param {string} type 'doc' | 'module' | 'lib' | 'space'
- * @param {object|array} orders {key: order, ...} | [key, ...]
- */
- function sortItems(type, orders)
- {
- if(Array.isArray(orders)) orders = formatOrders(orders, type === 'lib');
- const sortMethods = {doc: 'sortDoc', module: 'sortCatalog', lib: 'sortDoclib'};
- if(!sortMethods[type]) return console.error(`[DocApp] Invalid sort type: ${type}`);
- const url = $.createLink('doc', sortMethods[type]);
- return $.ajaxSubmit({
- url,
- data: {orders: JSON.stringify(orders)},
- onSuccess: function()
- {
- const items = Object.keys(orders).map(id => ({id: +id, order: orders[id]}));
- getDocApp().update(type, items);
- }
- });
- }
- /**
- * 获取界面上条目排序选项。
- * Get the sortable options on the doc UI.
- *
- * @param {string} type 'doc' | 'doc-module' | 'module' | 'lib' | 'space'
- */
- function getSortableOptions(type)
- {
- const canSortDocModule = hasPriv('sortModule') || hasPriv('sortDoc');
- if((type === 'doc-module' && canSortDocModule) || (type === 'lib' && hasPriv('sortDoclib')))
- {
- const getItemType = (key) => key[0] === 'm' ? 'module' : (key[0] === 'l' ? 'lib' : 'doc');
- return {
- sortable: {handle: '.sort-handler'},
- canSortTo: function(event)
- {
- let fromKey = event.dragged.getAttribute('z-key');
- let toKey = event.related.getAttribute('z-key');
- if(!fromKey || !toKey) return false;
- const fromType = getItemType(fromKey);
- const toType = getItemType(toKey);
- if (fromType !== toType) return false;
- return true;
- },
- onSort: function(event, orders)
- {
- const fromKey = event.item.getAttribute('z-key');
- if(!fromKey || !orders.length) return;
- const fromType = getItemType(fromKey);
- const orderedList = [];
- orders.forEach((key, index) =>
- {
- const keyType = getItemType(key);
- if(keyType !== fromType) return;
- if(fromType !== 'doc') key = key.substring(1);
- orderedList.push(+key);
- });
- if(fromType === 'doc')
- {
- const docApp = getDocApp();
- const doc = docApp.getDoc(orderedList[0]);
- const lib = doc ? docApp.getLib(doc.lib) : null;
- if(lib && typeof lib.data.orderBy === 'string' && lib.data.orderBy.endsWith('desc')) orderedList.reverse();
- }
- sortItems(fromType, orderedList);
- }
- }
- }
- }
- window.checkResponse = function(res)
- {
- if(typeof res === 'string') res = JSON.parse(res);
- if(typeof res !== 'object' || !res) return true;
- if(res.load === 'login')
- {
- if(res.message) zui.Modal.alert(res.message).then(() => $.apps.logout());
- else $.apps.logout();
- return false;
- }
- return true;
- }
- /**
- * 获取文档详情侧边栏标签页定义。
- * Get the doc view sidebar tabs.
- *
- * @param {object} doc
- */
- window.getDocViewSidebarTabs = function(doc, info)
- {
- if(isApiLib())
- {
- const lang = getDocAppLang();
- if(info.isNewDoc || info.mode === 'create') return [];
- return [
- {key: 'info', icon: 'info', title: lang.docInfo},
- info.mode === 'edit' ? null : {key: 'outline', icon: 'list-box', title: lang.docOutline},
- {key: 'history', icon: 'file-log', title: lang.history},
- ].filter(Boolean);
- }
- let tabList = [];
- if(info.isNewDoc)
- {
- tabList.push({key: 'outline', icon: 'list-box', title: getLang('docOutline')});
- }
- else
- {
- tabList.push(
- {key: 'outline', icon: 'list-box', title: getLang('docOutline')},
- {key: 'history', icon: 'file-log', title: getLang('history')}
- );
- }
- if(info.mode == 'view' && doc.status != 'draft' && !doc.api)
- {
- tabList.push(
- {
- key : 'relateObject',
- icon : 'link',
- title : getLang('relateObject'),
- render: function(doc){return {fetcher: $.createLink('doc', 'ajaxGetRelatedObjects', `docID=${doc.id}`)}}
- });
- }
- return tabList;
- }
- function getSpaceFetcher(spaceType, spaceID = 0)
- {
- if(spaceType === 'product')
- {
- return $.createLink('product', 'ajaxGetDropMenu', `productID=${spaceID}&module=doc&method=app&extra=&from=&useLink=0`);
- }
- if(spaceType === 'project')
- {
- return $.createLink('project', 'ajaxGetDropMenu', `projectID=${spaceID}&module=doc&method=app&extra=&useLink=0`);
- }
- }
- function initOfficePreview(options)
- {
- if(options.canPreviewOffice && options.fileInfoUrl)
- {
- const officeTypes = new Set(['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf']);
- zui.Editor.setGlobalConfig(
- {
- canPreviewFile: (file) => {
- const extension = file.name.split('.').pop();
- return officeTypes.has(extension);
- },
- onPreviewFile: (file) => {
- const doc = getDocApp().doc || {data: {id: 0}};
- $.getJSON(zui.formatString(options.fileInfoUrl, {
- gid: btoa(`g-${file.key}`),
- objectType: 'doc',
- objectID: doc.data.id,
- title: '',
- extra: '',
- })).then(res => {
- if(res.result === 'success' && res.file)
- {
- const editable = doc.data.editable !== false;
- window.open($.createLink('file', 'download', `fileID=${res.file.id}&mouse=left&edit=${editable ? '0' : 'never'}`), '_blank');
- }
- });
- }
- });
- }
- if(options.privs.downloadFile === false) zui.Editor.setGlobalConfig({canDownloadFile: (file) => false});
- }
- /**
- * 处理导入的文档快照。
- * Handle the imported doc snapshot.
- */
- function handleImportDocSnapshot(snapshot)
- {
- const forEachBlock = (blocks, callback) =>
- {
- blocks.forEach(block =>
- {
- callback(block);
- if(block.children) forEachBlock(block.children, callback);
- });
- };
- const requestType = config.requestType.toUpperCase();
- const fixUrl = (url, method, paramList) =>
- {
- const replaceOrign = url => {
- try
- {
- const urlObj = new URL(url);
- if(urlObj.origin != location.origin)
- {
- urlObj.protocol = location.protocol;
- urlObj.host = location.host;
- return urlObj.toString();
- }
- return url;
- }
- catch
- {
- return url;
- }
- };
- const link = $.parseLink(replaceOrign(url), 'auto');
- if(link.requestType.toUpperCase() === requestType || method.toLowerCase() !== link.methodName.toLowerCase()) return url
- return `${location.origin}${$.createLink('doc', method, paramList.map((p, i) => [p, link.vars[i][1]]))}`;
- };
- /* Fix custom block with fetcher in difference request type. */
- forEachBlock(snapshot.blocks.children, block =>
- {
- if(block.flavour !== 'affine:embed-zui-custom') return;
- const content = block.props.content;
- if(!content || typeof content !== 'object') return;
- if(content.fetcher) content.fetcher = fixUrl(content.fetcher, 'zentaoList', ['type', 'blockID']);
- if(content.exportUrl) content.exportUrl = fixUrl(content.exportUrl, 'ajaxExportZentaoList', ['blockID']);
- });
- return snapshot;
- }
- /**
- * 设置文档应用组件选项。
- * Set the doc app options.
- */
- window.setDocAppOptions = function(_, options)
- {
- docAppData.currentUser = options.currentUser;
- docAppData.currentSpaceType = options.spaceType;
- docAppData.userPrivs = options.privs;
- docAppData.docLangData = options.langData;
- initOfficePreview(options);
- return $.extend(
- {
- editorProps : {onImportSnapshot: handleImportDocSnapshot},
- defaultState : {listType: '', libReleaseMap: {}},
- commands : commands,
- customRenders : customRenders,
- onCreateDoc : docAppData.userPrivs.create ? handleCreateDoc : null,
- onSaveDoc : docAppData.userPrivs.edit ? handleSaveDoc : null,
- canMoveDoc : canMoveDoc,
- onSwitchView : handleSwitchView,
- getActions : getActions,
- getTableOptions : options.docViewer ? null : getTableOptions,
- getFilterTypes : getFilterTypes,
- isMatchFilter : isMatchFilter,
- getSortableOptions : getSortableOptions,
- getDocViewSidebarTabs: getDocViewSidebarTabs,
- getSpaceFetcher : getSpaceFetcher,
- showDocOutline : true,
- showDocHistory : true,
- $onDestroy : handleDocAppDestroy,
- }, window.docAppOptions, options);
- };
- window.docAppActions = actionsMap;
- window.docAppCommands = commands;
- window.docAppCustomRenders = customRenders;
- window.getDocApp = getDocApp;
- window.getDocAppLang = getLang;
- window.docAppHasPriv = hasPriv;
- window.getFileActions = function(file)
- {
- let fileActions = [];
- let canPreview = false;
- let officeTypes = 'doc|docx|xls|xlsx|ppt|pptx|pdf';
- let isOfficeFile = officeTypes.includes(file.extension);
- let previewExtension = 'txt|jpg|jpeg|gif|png|bmp|mp4';
- if(previewExtension.includes(file.extension)) canPreview = true;
- if(libreOfficeTurnon && isOfficeFile) canPreview = true;
- if(canPreview)
- {
- let previewAction = {icon: 'eye', title: previewLang, url: previewLink.replace('{id}', file.id).replace('\\', ''), className: 'text-primary', target: '_blank'};
- if(!isOfficeFile)
- {
- previewAction['data-toggle'] = 'modal';
- previewAction['data-size'] = 'lg';
- delete previewAction.target;
- }
- fileActions.push(previewAction);
- }
- fileActions.push({icon: 'download', title: downloadLang, url: downloadLink.replace('{id}', file.id).replace('\\', ''), className: 'text-primary', target: '_blank'});
- return fileActions;
- };
- window.useHocuspocus = function(app)
- {
- if(config.vision !== 'rnd') return false;
- return enableHocuspocus && app.spaceType !== 'mine';
- };
- let lastDisconnectMessager = null;
- window.onHocuspocusConnect = function(app)
- {
- if(app.spaceType === 'mine') return;
- lastDisconnectMessager && lastDisconnectMessager.hide();
- lastDisconnectMessager = null;
- zui.Messager.show({
- content: hocuspocusConnect,
- type: 'success',
- time: 3000,
- });
- };
- window.onHocuspocusDisconnect = function(app)
- {
- if(app.spaceType === 'mine') return;
- lastDisconnectMessager && lastDisconnectMessager.hide();
- lastDisconnectMessager = zui.Messager.show({
- content: hocuspocusDisconnect,
- type: 'danger',
- time: 0,
- });
- };
- window.onAuthenticationFailed = function(app)
- {
- if(app.spaceType === 'mine') return;
- zui.Messager.show({
- content: needReadable,
- type: 'danger',
- time: 3000,
- });
- };
- window.onDocAppModeChange = function()
- {
- lastDisconnectMessager && lastDisconnectMessager.hide();
- lastDisconnectMessager = null;
- };
- window.getPageFormHelper = function()
- {
- const docApp = getDocApp();
- if(docApp.mode === 'edit' && !isApiDoc(docApp.doc))
- {
- const fields =
- {
- title: (_, $scope) => $scope.find('.doc-editor-title'),
- content: (_, $scope) => $scope.find('[z-use-editor]'),
- };
- return zui.formHelper($(docApp.element).find('.doc-editor'), {fields: fields});
- }
- };
|