mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-10-04 22:31:02 +00:00
* Escape Project Metadata in the Project Page and Restrict Accessory Opening The Project page rendered the model and profile name, author, description and accessory file names from the 3MF as live HTML. Names, authors and file names are now set as text, and the file list is built from DOM nodes with bound click handlers instead of concatenated markup. Descriptions can legitimately carry rich-text HTML, so they are rebuilt from an inert DOMParser document, keeping only plain formatting tags, http(s) links and http(s) images, with every other attribute dropped. Opening an accessory from the page now only launches regular files that lie inside the project's extracted auxiliary directory. The containment check is a new libslic3r helper, is_absolute_path_within_root, built on is_path_within_root so symlinks leading out of the root are rejected too. * Tighten Project Page Description Rendering and Keep More Formatting Link and image URLs in descriptions must now start with an http or https scheme as written and parse as such with the URL parser. Preview images are built as DOM nodes like the file list, and accessory names show their full text as a tooltip. Descriptions keep more plain formatting: del, ins, figure, figcaption, dl, dt, dd, caption, q, abbr, kbd and wbr, plus alt, title, width and height on images, colspan and rowspan on table cells and start on ordered lists. Numeric attributes must be plain integers. Embedded YouTube players become a link to the video. * Confirm Before Opening Program Attachments and Load Only HTTPS Images Opening a project attachment whose type runs as a program or script (executables, installers, shortcuts, shell and PowerShell scripts, macOS command files and apps, Linux desktop entries) now asks for confirmation first. The check lives in libslic3r as is_executable_file_name and ignores the trailing dots and spaces Windows strips from file names. Images in project descriptions are kept only when they load over https, so opening the Project tab no longer issues plain-http requests. * Open Project Attachments Through One Guarded Helper The Edit Project Info view launched attachments directly, without the checks the project page has. Both now call desktop_open_project_attachment, which checks that the file is inside the auxiliary directory, asks for confirmation where needed and then opens it. The auxiliary root was built through encode_path, which returns code page bytes on Windows, while boost::filesystem reads a narrow string as UTF-8. With a non-ASCII temporary directory the root never matched and no attachment opened. It is now built from the UTF-8 path directly. The list of program extensions could not be kept complete and let unknown types open without a prompt. It is replaced by is_safe_to_open_file_name, a list of plain document, image, model and video types that open directly. Everything else asks first.
702 lines
18 KiB
JavaScript
702 lines
18 KiB
JavaScript
var ModelSwiper=null;
|
|
var ProfileSwiper=null;
|
|
|
|
function OnInit()
|
|
{
|
|
console.log(" 页面加载完成 ");
|
|
//翻译页面
|
|
TranslatePage();
|
|
|
|
//获取数据
|
|
RequestProjectInfo();
|
|
|
|
//图片滚动器的初始化
|
|
// mySwiper = new Swiper('.swiper', {
|
|
// loop:true,
|
|
// slidesPerView : 4,
|
|
// slidesPerGroup : 1,
|
|
// spaceBetween: 8,
|
|
// navigation: {
|
|
// slidesPerGroup :4,
|
|
// nextEl: '.swiper-button-next',
|
|
// prevEl: '.swiper-button-prev',
|
|
// },
|
|
// autoplay: {
|
|
// delay: 3000,
|
|
// stopOnLastSlide: false,
|
|
// disableOnInteraction: true,
|
|
// disableOnInteraction: false
|
|
// }
|
|
// });
|
|
|
|
//锚点跟踪
|
|
AddScrollEvent();
|
|
|
|
//测试代码
|
|
//ShowProjectInfo(null);
|
|
//ShowProjectInfo(TestProjectData);
|
|
//ShowProjectInfo(null);
|
|
//ShowProjectInfo(TestProjectData);
|
|
// $('#ModelPreviewList').viewer({
|
|
// title: false,
|
|
// fullsreen: false,
|
|
// zIndex: 999999,
|
|
// interval: 3000
|
|
// });
|
|
// $('#ModelPreviewList').viewer('update');
|
|
}
|
|
|
|
function AddScrollEvent()
|
|
{
|
|
//跟踪页面位置
|
|
$('#Info_Inside_Board').scroll(function(){
|
|
//checkElementDistance("Info_Inside_Board", 'Model_Basic')
|
|
//checkElementDistance("Info_Inside_Board", 'Model_Accessories');
|
|
//checkElementDistance("Info_Inside_Board", 'Model_Profile');
|
|
let ParentItem=$('#Info_Inside_Board');
|
|
|
|
let BItem=$('#Model_Basic');
|
|
let AItem=$('#Model_Accessories');
|
|
let PItem=$('#Model_Profile');
|
|
|
|
let BTop=Math.abs(BItem.offset().top - ParentItem.offset().top);
|
|
let BBottom=Math.abs(BItem.offset().top + BItem.innerHeight() - ParentItem.offset().top);
|
|
let ATop=Math.abs(AItem.offset().top - ParentItem.offset().top);
|
|
let ABottom=Math.abs(AItem.offset().top + AItem.innerHeight() - ParentItem.offset().top);
|
|
let PTop=Math.abs(PItem.offset().top - ParentItem.offset().top);
|
|
let PBottom=Math.abs(PItem.offset().top + PItem.innerHeight() - ParentItem.offset().top);
|
|
|
|
console.log('------positon-----');
|
|
console.log("B: "+BTop+'-'+BBottom);
|
|
console.log("A: "+ATop+'-'+ABottom);
|
|
console.log("P: "+PTop+'-'+PBottom);
|
|
|
|
let nMin=Math.min(BTop,BBottom,ATop,ABottom,PTop,PBottom );
|
|
|
|
if( nMin==BTop || nMin==BBottom)
|
|
{
|
|
OnMenuSelected('Model_Basic');
|
|
}
|
|
else if( nMin==ATop || nMin==ABottom)
|
|
{
|
|
OnMenuSelected('Model_Accessories');
|
|
}
|
|
else if( nMin==PTop || nMin==PBottom)
|
|
{
|
|
OnMenuSelected('Model_Profile');
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
function OnMenuClick( strID )
|
|
{
|
|
scrollLocation("Info_Inside_Board",strID);
|
|
|
|
//OnMenuSelected(strID);
|
|
}
|
|
|
|
function OnMenuSelected(strID)
|
|
{
|
|
console.log("MenuSelected: "+strID);
|
|
|
|
//UI
|
|
$('.LeftProcessBar').removeClass('ProcessBarSelected');
|
|
switch(strID)
|
|
{
|
|
case 'Model_Basic':
|
|
$('#Info_ProcessBar').addClass('ProcessBarSelected');
|
|
break;
|
|
case 'Model_Accessories':
|
|
$('#File_ProcessBar').addClass('ProcessBarSelected');
|
|
break;
|
|
case 'Model_Profile':
|
|
$('#Profile_ProcessBar').addClass('ProcessBarSelected');
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------自动滚动跟踪效果---------*/
|
|
function scrollLocation(FatherID, ChildID)
|
|
{
|
|
let FItem=$('#'+FatherID);
|
|
let CItem=$('#'+ChildID);
|
|
|
|
let Tmp=CItem.offset().top - FItem.offset().top + FItem.scrollTop();
|
|
|
|
// father.scrollTop(
|
|
// scrollTo.offset().top - father.offset().top + father.scrollTop()
|
|
// );
|
|
// Or you can animate the scrolling:
|
|
FItem.animate({scrollTop:Tmp}, 400);
|
|
};
|
|
|
|
/*----------处理C++的消息-------*/
|
|
function Request3MFInfo()
|
|
{
|
|
var tSend={};
|
|
tSend['sequence_id']=Math.round(new Date() / 1000);
|
|
tSend['command']="request_3mf_info";
|
|
|
|
SendWXMessage( JSON.stringify(tSend) );
|
|
}
|
|
|
|
function HandleStudio(pVal)
|
|
{
|
|
let strCmd=pVal['command'];
|
|
|
|
if(strCmd=='show_3mf_info')
|
|
{
|
|
ShowProjectInfo( pVal['model'] );
|
|
}
|
|
else if(strCmd=='clear_3mf_info')
|
|
{
|
|
ShowProjectInfo( null );
|
|
}
|
|
}
|
|
|
|
function ShowProjectInfo( p3MF )
|
|
{
|
|
if(p3MF==null)
|
|
{
|
|
$('#EmptyArea').css('display','flex');
|
|
$('#WholeArea').hide();
|
|
return;
|
|
}
|
|
|
|
//Check Data
|
|
let pModel=p3MF['model'];
|
|
let pFile=p3MF['file'];
|
|
let pProfile=p3MF['profile'];
|
|
|
|
ShowModelInfo( pModel );
|
|
ShowFileInfo( pFile );
|
|
ShowProfilelInfo(pProfile);
|
|
|
|
TranslatePage();
|
|
$('#EmptyArea').hide();
|
|
$('#WholeArea').show();
|
|
|
|
// mySwiper = new Swiper('.swiper', {
|
|
// loop:true,
|
|
// spaceBetween: 8,
|
|
// navigation: {
|
|
// slidesPerGroup :4,
|
|
// nextEl: '.swiper-button-next',
|
|
// prevEl: '.swiper-button-prev',
|
|
// },
|
|
// autoplay: {
|
|
// delay: 3000,
|
|
// stopOnLastSlide: false,
|
|
// disableOnInteraction: true,
|
|
// disableOnInteraction: false
|
|
// }
|
|
// });
|
|
|
|
AddScrollEvent();
|
|
}
|
|
|
|
function ShowModelInfo( pModel )
|
|
{
|
|
//==========Model Info==========
|
|
let sModelName=decodeURIComponent(pModel.name);
|
|
let sModelAuthor=decodeURIComponent(pModel.author);
|
|
let UploadType=pModel.upload_type.toLowerCase();
|
|
let sLicence=pModel.license.toUpperCase();
|
|
let sModelDesc=decodeURIComponent(pModel.description);
|
|
|
|
if( pModel.hasOwnProperty('model_id') )
|
|
{
|
|
let m_id=pModel['model_id']+'';
|
|
UpdateModelID( m_id.trim() );
|
|
}
|
|
|
|
SendWXDebugInfo("Model Name: "+sModelName);
|
|
|
|
$('#ModelName').text(sModelName);
|
|
$('#ModelName').attr('title',sModelName);
|
|
$('#ModelAuthorName').text(sModelAuthor);
|
|
|
|
switch(UploadType)
|
|
{
|
|
case 'remix':
|
|
$('#ModelAuthorType').attr('tid','t93');
|
|
break;
|
|
case 'shared':
|
|
$('#ModelAuthorType').attr('tid','t94');
|
|
break;
|
|
case 'origin':
|
|
case 'profile':
|
|
default:
|
|
$('#ModelAuthorType').attr('tid','t92');
|
|
break;
|
|
}
|
|
|
|
switch(sLicence)
|
|
{
|
|
case 'CC0':
|
|
$('#ModelLicenceImg img').attr('src','img/cc-zero.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY':
|
|
$('#ModelLicenceImg img').attr('src','img/by.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY-SA':
|
|
$('#ModelLicenceImg img').attr('src','img/by-sa.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY-ND':
|
|
$('#ModelLicenceImg img').attr('src','img/by-nd.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY-NC':
|
|
$('#ModelLicenceImg img').attr('src','img/by-nc.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY-NC-SA':
|
|
$('#ModelLicenceImg img').attr('src','img/by-nc-sa.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
case 'BY-NC-ND':
|
|
$('#ModelLicenceImg img').attr('src','img/by-nc-nd.png');
|
|
$('#ModelLicenceImg').show();
|
|
break;
|
|
default:
|
|
$('#ModelLicenceImg').hide();
|
|
break;
|
|
}
|
|
|
|
$('#Model_Desc').empty().append( SanitizeDescHtml( html_decode(sModelDesc) ) );
|
|
|
|
let ModelPreviewList=pModel.preview_img;
|
|
let TotalPreview=ModelPreviewList.length;
|
|
|
|
if( ModelSwiper!=null )
|
|
{
|
|
ModelSwiper.destroy(true,true);
|
|
ModelSwiper=null;
|
|
}
|
|
|
|
if(TotalPreview>0)
|
|
{
|
|
$('#ModelPreviewList').empty();
|
|
for(let pn=0;pn<TotalPreview;pn++)
|
|
{
|
|
//let FTmpPath=decodeURIComponent(ModelPreviewList[pn]);
|
|
let FTmpPath=ModelPreviewList[pn]['filepath'];
|
|
|
|
$('#ModelPreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
|
}
|
|
|
|
$('#Model_Preview_Image').viewer({
|
|
title: false,
|
|
fullsreen: false,
|
|
zIndex: 11,
|
|
interval: 3000
|
|
});
|
|
$('#Model_Preview_Image').viewer('update');
|
|
|
|
//Initial Swiper
|
|
if(TotalPreview==1)
|
|
{
|
|
ModelSwiper = new Swiper('#Model_Preview_Image.swiper', {
|
|
spaceBetween: 8
|
|
});
|
|
|
|
$('#Model_Preview_Image .swiper-button-prev').hide();
|
|
$('#Model_Preview_Image .swiper-button-next').hide();
|
|
$('#Model_Preview_Image .swiper-pagination').hide();
|
|
}
|
|
else
|
|
{
|
|
$('#Model_Preview_Image .swiper-button-prev').show();
|
|
$('#Model_Preview_Image .swiper-button-next').show();
|
|
$('#Model_Preview_Image .swiper-pagination').show();
|
|
|
|
ModelSwiper = new Swiper('#Model_Preview_Image.swiper', {
|
|
loop:false,
|
|
spaceBetween: 8,
|
|
navigation: {
|
|
nextEl: '.swiper-button-next',
|
|
prevEl: '.swiper-button-prev',
|
|
},
|
|
autoplay: {
|
|
delay: 3000,
|
|
stopOnLastSlide: false,
|
|
disableOnInteraction: false
|
|
},
|
|
pagination: {
|
|
el: '.swiper-pagination',
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#Model_Preview_Image').show();
|
|
}
|
|
else
|
|
{
|
|
$('#Model_Preview_Image').hide();
|
|
}
|
|
}
|
|
|
|
function ShowFileInfo( pFile )
|
|
{
|
|
let pBOM=pFile['BOM'];
|
|
let pAssembly=pFile['Assembly'];
|
|
let pOther=pFile['Other'];
|
|
|
|
let BTotal=pBOM.length;
|
|
let ATotal=pAssembly.length;
|
|
let OTotal=pOther.length;
|
|
let fTotal=BTotal+ATotal+OTotal;
|
|
|
|
//Total Number
|
|
$('#FileTotalNum').html(fTotal);
|
|
$('#BOMTotalNum').html(BTotal);
|
|
$('#AssemblyTotalNum').html(ATotal);
|
|
$('#OtherFileTotalNum').html(OTotal);
|
|
|
|
//BOM
|
|
if(BTotal==0)
|
|
{
|
|
$('#FILE_BOM_List').hide();
|
|
}
|
|
else
|
|
{
|
|
ConstructFileHtml('FILE_BOM_List',pBOM);
|
|
}
|
|
|
|
//Assembly
|
|
if(ATotal==0)
|
|
{
|
|
$('#FILE_ASSEMBLY_List').hide();
|
|
}
|
|
else
|
|
{
|
|
ConstructFileHtml('FILE_ASSEMBLY_List',pAssembly);
|
|
}
|
|
|
|
//Other
|
|
if(OTotal==0)
|
|
{
|
|
$('#FILE_OTHER_List').hide();
|
|
}
|
|
else
|
|
{
|
|
ConstructFileHtml('FILE_OTHER_List',pOther);
|
|
}
|
|
|
|
//zIndex
|
|
$('.ImageIcon').viewer({
|
|
title: false,
|
|
fullsreen: false,
|
|
zIndex: 11,
|
|
interval: 3000
|
|
});
|
|
$('.ImageIcon').viewer('update');
|
|
}
|
|
|
|
|
|
var ExcelTail=['xlsx','xlsm','xlsb','csv','xls','xltx','xltm','xlt','xlam','xla'];
|
|
var PdfTail=['pdf','fdf','xfdf','xdp','ppdf','ofd'];
|
|
var ImgTail=['jpg','jpeg','bmp','gif','svg','png','bmp'];
|
|
|
|
var ImgID=0;
|
|
|
|
function ConstructFileHtml( ID, pItem )
|
|
{
|
|
let fTotal=pItem.length;
|
|
|
|
let pBoard=$('#'+ID+' .FileListBoard');
|
|
pBoard.empty();
|
|
for( let f=0;f<fTotal;f++ )
|
|
{
|
|
let pOne=pItem[f];
|
|
|
|
let tPath=pOne['filepath'];
|
|
let tName=decodeURIComponent(pOne['filename']);
|
|
|
|
let sTail=getFileTail(tName).toLowerCase();
|
|
|
|
//File or Image
|
|
let strClass='FileIcon';
|
|
let ImgPath='';
|
|
|
|
if( $.inArray( sTail, ImgTail )>=0 )
|
|
{
|
|
strClass='ImageIcon';
|
|
|
|
ImgPath=tPath;
|
|
}
|
|
else if( $.inArray( sTail, ExcelTail )>=0 )
|
|
{
|
|
ImgPath='img/excel.png';
|
|
}
|
|
else if( $.inArray( sTail, PdfTail )>=0 )
|
|
{
|
|
ImgPath='img/pdf.png';
|
|
}
|
|
else
|
|
{
|
|
ImgPath='img/default.png';
|
|
}
|
|
|
|
//Add html. File names come from the 3MF, so build the nodes rather than concatenating markup.
|
|
let pIconImg=$('<img />').attr('src',ImgPath);
|
|
let pMenu=$('<div class="FileMenu"><img src="img/s.svg" /></div>');
|
|
if( strClass!='ImageIcon' )
|
|
{
|
|
pMenu.on('click', function(){ OnClickOpenFile(tPath); });
|
|
}
|
|
else
|
|
{
|
|
ImgID++;
|
|
let TmpImgID="AF"+ImgID;
|
|
|
|
pIconImg.attr('id',TmpImgID);
|
|
pMenu.on('click', function(){ OnClickOpenImage(TmpImgID); });
|
|
}
|
|
|
|
let pFileItem=$('<div class="FileItem"></div>');
|
|
pFileItem.append( $('<div></div>').addClass(strClass).append(pIconImg) );
|
|
pFileItem.append( $('<div class="FileText"></div>').append( $('<div class="FileName"></div>').text(tName).attr('title',tName) ) );
|
|
pFileItem.append( pMenu );
|
|
pBoard.append( pFileItem );
|
|
}
|
|
|
|
if( fTotal>0 )
|
|
$('#'+ID).show();
|
|
}
|
|
|
|
|
|
// Descriptions are untrusted 3MF metadata that may carry rich-text HTML (e.g. from MakerWorld).
|
|
// Rebuild them from an inert parse, keeping only plain formatting tags and http(s) links and images.
|
|
var DescAllowedTags=['P','BR','B','STRONG','I','EM','U','S','STRIKE','DEL','INS','SUB','SUP','SMALL','MARK',
|
|
'Q','ABBR','KBD','WBR','H1','H2','H3','H4','H5','H6','UL','OL','LI','DL','DT','DD','BLOCKQUOTE','PRE','CODE',
|
|
'HR','SPAN','DIV','FIGURE','FIGCAPTION','TABLE','CAPTION','THEAD','TBODY','TFOOT','TR','TH','TD','A','IMG'];
|
|
// Plain attributes kept per tag; the numeric ones must be plain non-negative integers.
|
|
var DescAllowedAttrs={'IMG':['alt','title','width','height'],'TD':['colspan','rowspan'],'TH':['colspan','rowspan'],'OL':['start']};
|
|
var DescNumericAttrs=['width','height','colspan','rowspan','start'];
|
|
// Dropped together with their content; any other unknown tag is unwrapped to its children.
|
|
var DescDroppedTags=['SCRIPT','STYLE','TEMPLATE','NOSCRIPT','TEXTAREA','TITLE','IFRAME','FRAME','OBJECT','EMBED','SVG','MATH'];
|
|
|
|
function IsHttpUrl( strUrl )
|
|
{
|
|
// The scheme must be written as is, so nothing the URL parser would strip can precede or split it.
|
|
if( typeof strUrl!='string' || !/^https?:/i.test(strUrl) )
|
|
return false;
|
|
try
|
|
{
|
|
let sProtocol=new URL(strUrl).protocol;
|
|
return sProtocol=='http:' || sProtocol=='https:';
|
|
}
|
|
catch(e)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Images load as soon as the page opens, so only https sources are kept: no plain-http requests to the local network.
|
|
function IsHttpsUrl( strUrl )
|
|
{
|
|
return IsHttpUrl(strUrl) && new URL(strUrl).protocol=='https:';
|
|
}
|
|
|
|
// Embedded YouTube players become a plain link to the video.
|
|
function GetYouTubeEmbedUrl( pNode )
|
|
{
|
|
let sSrc=pNode.getAttribute('src');
|
|
if( !IsHttpUrl(sSrc) )
|
|
return null;
|
|
let pUrl=new URL(sSrc);
|
|
return ( pUrl.origin=='https://www.youtube.com' && pUrl.pathname.indexOf('/embed/')==0 ) ? pUrl.href : null;
|
|
}
|
|
|
|
function CopyDescNodes( pSrc, pDst )
|
|
{
|
|
for( let pNode=pSrc.firstChild;pNode!=null;pNode=pNode.nextSibling )
|
|
{
|
|
if( pNode.nodeType==Node.TEXT_NODE )
|
|
{
|
|
pDst.appendChild( document.createTextNode(pNode.nodeValue) );
|
|
continue;
|
|
}
|
|
if( pNode.nodeType!=Node.ELEMENT_NODE )
|
|
continue;
|
|
|
|
let sTag=pNode.nodeName.toUpperCase();
|
|
if( sTag=='IFRAME' )
|
|
{
|
|
let sVideoUrl=GetYouTubeEmbedUrl(pNode);
|
|
if( sVideoUrl!=null )
|
|
{
|
|
let pLink=document.createElement('A');
|
|
pLink.setAttribute('href',sVideoUrl);
|
|
pLink.textContent=sVideoUrl;
|
|
pDst.appendChild(pLink);
|
|
}
|
|
continue;
|
|
}
|
|
if( $.inArray(sTag,DescDroppedTags)>=0 )
|
|
continue;
|
|
if( $.inArray(sTag,DescAllowedTags)<0 )
|
|
{
|
|
CopyDescNodes(pNode,pDst);
|
|
continue;
|
|
}
|
|
|
|
let pElem=document.createElement(sTag);
|
|
if( sTag=='A' && IsHttpUrl(pNode.getAttribute('href')) )
|
|
pElem.setAttribute('href',pNode.getAttribute('href'));
|
|
else if( sTag=='IMG' )
|
|
{
|
|
if( !IsHttpsUrl(pNode.getAttribute('src')) )
|
|
continue;
|
|
pElem.setAttribute('src',pNode.getAttribute('src'));
|
|
}
|
|
$.each( DescAllowedAttrs[sTag]||[], function(i,sAttr){
|
|
let sValue=pNode.getAttribute(sAttr);
|
|
if( sValue!=null && ( $.inArray(sAttr,DescNumericAttrs)<0 || /^\d+$/.test(sValue) ) )
|
|
pElem.setAttribute(sAttr,sValue);
|
|
});
|
|
CopyDescNodes(pNode,pElem);
|
|
pDst.appendChild(pElem);
|
|
}
|
|
}
|
|
|
|
function SanitizeDescHtml( strHtml )
|
|
{
|
|
let pFragment=document.createDocumentFragment();
|
|
// A DOMParser document is inert: it runs no scripts and loads no resources.
|
|
let pDoc=new DOMParser().parseFromString(strHtml,'text/html');
|
|
if( pDoc && pDoc.body )
|
|
CopyDescNodes(pDoc.body,pFragment);
|
|
return pFragment;
|
|
}
|
|
|
|
function ShowProfilelInfo( pProfile )
|
|
{
|
|
//==========Profile Info==========
|
|
let sProfileName=decodeURIComponent(pProfile.name);
|
|
let sProfileAuthor=decodeURIComponent(pProfile.author);
|
|
let sProfileDesc=decodeURIComponent(pProfile.description);
|
|
|
|
$('#ProfileName').text(sProfileName);
|
|
$('#ProfileAuthor').text(sProfileAuthor);
|
|
|
|
$('#Profile_Desc').empty().append( SanitizeDescHtml( html_decode(sProfileDesc) ) );
|
|
|
|
let ProfilePreviewList=pProfile.preview_img;
|
|
let TotalPreview=ProfilePreviewList.length;
|
|
|
|
if( ProfileSwiper!=null )
|
|
{
|
|
ProfileSwiper.destroy(true,true);
|
|
ProfileSwiper=null;
|
|
}
|
|
|
|
if(TotalPreview>0)
|
|
{
|
|
$('#ProfilePreviewList').empty();
|
|
for(let pn=0;pn<TotalPreview;pn++)
|
|
{
|
|
let FTmpPath=ProfilePreviewList[pn]['filepath'];
|
|
|
|
$('#ProfilePreviewList').append( $('<div class="swiper-slide"></div>').append( $('<img class="Model_PrevImg" />').attr('src',FTmpPath) ) );
|
|
}
|
|
|
|
$('#Profile_Preview_Image').viewer({
|
|
title: false,
|
|
fullsreen: false,
|
|
zIndex: 11,
|
|
interval: 3000
|
|
});
|
|
$('#Profile_Preview_Image').viewer("update");
|
|
|
|
//Init Profile Swiper
|
|
if(TotalPreview==1)
|
|
{
|
|
ProfileSwiper = new Swiper('#Profile_Preview_Image.swiper', {
|
|
spaceBetween: 8
|
|
});
|
|
|
|
$('#Profile_Preview_Image .swiper-button-prev').hide();
|
|
$('#Profile_Preview_Image .swiper-button-next').hide();
|
|
$('#Profile_Preview_Image .swiper-pagination').hide();
|
|
}
|
|
else
|
|
{
|
|
$('#Profile_Preview_Image .swiper-button-prev').show();
|
|
$('#Profile_Preview_Image .swiper-button-next').show();
|
|
$('#Profile_Preview_Image .swiper-pagination').show();
|
|
|
|
ProfileSwiper = new Swiper('#Profile_Preview_Image.swiper', {
|
|
loop:false,
|
|
spaceBetween: 8,
|
|
navigation: {
|
|
nextEl: '.swiper-button-next',
|
|
prevEl: '.swiper-button-prev',
|
|
},
|
|
autoplay: {
|
|
delay: 3000,
|
|
stopOnLastSlide: false,
|
|
disableOnInteraction: false
|
|
},
|
|
pagination: {
|
|
el: '.swiper-pagination',
|
|
}
|
|
});
|
|
}
|
|
|
|
$('#Profile_Preview_Image').show();
|
|
}
|
|
else
|
|
{
|
|
$('#Profile_Preview_Image').hide();
|
|
}
|
|
}
|
|
|
|
|
|
//Push Command to C++
|
|
function RequestProjectInfo()
|
|
{
|
|
var tSend={};
|
|
tSend['sequence_id']=Math.round(new Date() / 1000);
|
|
tSend['command']="request_3mf_info";
|
|
|
|
SendWXMessage( JSON.stringify(tSend) );
|
|
}
|
|
|
|
function OnClickOpenFile( strFullPath )
|
|
{
|
|
var tSend={};
|
|
tSend['sequence_id']=Math.round(new Date() / 1000);
|
|
tSend['command']="open_3mf_accessory";
|
|
tSend['accessory_path']=strFullPath;
|
|
|
|
SendWXMessage( JSON.stringify(tSend) );
|
|
SendWXDebugInfo('----open accessory: '+strFullPath);
|
|
}
|
|
|
|
function OnClickOpenImage( F_ID )
|
|
{
|
|
$("img#"+F_ID).click();
|
|
}
|
|
|
|
function OnClickEditProjectInfo()
|
|
{
|
|
var tSend={};
|
|
tSend['sequence_id']=Math.round(new Date() / 1000);
|
|
tSend['command']="edit_project_info";
|
|
|
|
SendWXMessage( JSON.stringify(tSend) );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|