function mxODPicker(container, previewFn, getODFilesList, getODFileInfo, getRecentList, addToRecent, pickedFileCallback, errorFn, foldersOnly, backFn, withSubmitBtn, withThumbnail, initFolderPath, acceptAllFiles) { var previewHtml = ''; if (previewFn == null) { previewFn = renderFile; previewHtml = '
'; } if (getRecentList == null) { getRecentList = function() { var list = null; try { list = JSON.parse(localStorage.getItem('mxODPickerRecentList')); } catch(e){} return list; } } if (addToRecent == null) { addToRecent = function(file) { if (file == null) { return; } var recentList = getRecentList() || {}; delete file['@microsoft.graph.downloadUrl']; recentList[file.id] = file; localStorage.setItem('mxODPickerRecentList', JSON.stringify(recentList)); } } function _$(selector, elem) { elem = elem || document; return elem.querySelector(selector); }; function _$$(selector, elem) { elem = elem || document; return elem.querySelectorAll(selector); }; var html = '
' + '
OneDrive
' + '
' + mxUtils.htmlEntities(mxResources.get('files')) + '
' + '
' + mxUtils.htmlEntities(mxResources.get('recent')) + '
' + '
' + mxUtils.htmlEntities(mxResources.get('shared')) + '
' + '
' + mxUtils.htmlEntities(mxResources.get('sharepoint')) + '
' + '
' + '
' + '' + '
' + '
' + '' + '
' + '
' + '
' + previewHtml + (backFn? '
< ' + mxUtils.htmlEntities(mxResources.get('back')) + '
' : '') + (withSubmitBtn? '' : ''); var isDarkMode = window.Editor != null && Editor.isDarkMode != null && Editor.isDarkMode(); var css = '.odCatsList *, .odFilesSec * { user-select: none; }' + '.odCatsList {' + ' box-sizing: border-box;' + ' position:absolute;' + ' top:0px;' + ' bottom:50%;' + ' width:30%;' + ' border: 1px solid #CCCCCC;' + ' border-bottom:none;' + ' display: inline-block;' + ' overflow-x: hidden;' + ' overflow-y: auto;' + '}' + '.odCatsListLbl {' + ' height: 17px;' + ' color: #6D6D6D;' + ' font-size: 14px;' + ' font-weight: bold;' + ' line-height: 17px;' + ' margin: 10px 0 3px 5px;' + '}' + '.odFilesSec {' + ' box-sizing: border-box;' + ' position:absolute;' + ' left:30%;' + ' top:0px;' + ' bottom:50%;' + ' width: 70%;' + ' border: 1px solid #CCCCCC;' + ' border-left:none;' + ' border-bottom:none;' + ' display: inline-block;' + ' overflow: hidden;' + '}' + '.odFilesBreadcrumb {' + ' box-sizing: border-box;' + ' position:absolute;' + ' min-height: 32px;' + ' left:0px;' + ' right:20px;' + ' text-overflow:ellipsis;' + ' overflow:hidden;' + ' font-size: 13px;' + ' color: #6D6D6D;' + ' padding: 5px;' + '}' + '.odRefreshButton {' + ' box-sizing: border-box;' + ' position:absolute;' + ' right:0px;' + ' top:0px;' + ' padding: 4px;' + ' margin: 1px;' + ' height:24px;' + ' cursor:default;' + '}' + '.odRefreshButton>img {' + ' opacity:0.5;' + '}' + '.odRefreshButton:hover {' + ' background-color:#ddd;' + ' border-radius:50%;' + '}' + // '.odRefreshButton:hover {' + // ' background-color:#ddd;' + // ' border-radius:50%;' + // '}' + '.odRefreshButton:active {' + ' opacity:0.7;' + '}' + '.odFilesList {' + ' box-sizing: border-box;' + ' position:absolute;' + ' top:32px;' + ' bottom:0px;' + ' width: 100%;' + ' overflow-x: hidden;' + ' overflow-y: auto;' + '}' + '.odFileImg {' + ' width: 24px;' + ' padding-left: 5px;' + ' padding-right: 5px;' + '}' + '.odFileTitle {' + ' cursor: default;' + ' font-weight: normal;' + ' color: #666666 !important;' + ' width: calc(100% - 20px);' + ' white-space: nowrap;' + ' overflow: hidden;' + ' text-overflow: ellipsis;' + '}' + '.odFileListGrid {' + ' width: 100%;' + ' white-space: nowrap;' + ' font-size: 13px;' + ' box-sizing: border-box;' + ' border-spacing: 0;' + '}' + '.odOddRow {' + (isDarkMode ? '' : ' background-color: #eeeeee;') + '}' + '.odEvenRow {' + (isDarkMode ? '' : ' background-color: #FFFFFF;') + '}' + '.odRowSelected {' + ' background-color: #cadfff;' + '}' + '.odCatListTitle {' + ' box-sizing: border-box;' + ' height: 17px;' + ' cursor: default;' + ' color: #666666;' + ' font-size: 14px;' + ' line-height: 17px;' + ' margin: 5px 0 5px 0px;' + ' padding-left: 10px;' + '}' + '.odCatSelected {' + ' font-weight: bold;' + ' background-color: #cadfff;' + '}' + '.odEmptyFolder {' + ' height: 17px;' + ' color: #6D6D6D;' + ' font-size: 14px;' + ' font-weight: bold;' + ' line-height: 17px;' + ' margin: 10px 0 3px 5px;' + ' width: 100%;' + ' text-align: center;' + '}' + '.odBCFolder {' + ' cursor: pointer;' + ' color: #0432ff;' + '}' + '.odPreviewStatus {' + ' position:absolute;' + ' text-align:center;' + ' width:100%;' + ' top:50%;' + ' transform: translateY(-50%);' + ' font-size:13px;' + ' opacity:0.5;' + '}' + '.odPreview {' + ' position:absolute;' + ' overflow:hidden;' + ' border: 1px solid #CCCCCC;' + ' bottom:0px;' + ' top: 50%;' + ' left:0px;' + ' right:0px;' + '}' + '.odLinkBtn {' + ' position: absolute;' + ' font-size: 12px;' + ' cursor: pointer;' + ' color: #6D6D6D;' + ' left: 5px;' + ' bottom: 3px;' + '}' + '.odSubmitBtn {' + ' position: absolute;' + ' color: #333;' + ' right: 5px;' + ' bottom: 5px;' + '}'; var opts = { left: '50%', lines: 12, // The number of lines to draw length: 8, // The length of each line width: 3, // The line thickness radius: 5, // The radius of the inner circle rotate: 0, // The rotation offset color: '#000', // #rgb or #rrggbb speed: 1, // Rounds per second trail: 60, // Afterglow percentage shadow: false, // Whether to render a shadow hwaccel: false, // Whether to use hardware acceleration className: 'spinner', // The CSS class to assign to the spinner zIndex: 2e9 // The z-index (defaults to 2000000000) }; var spinner = new Spinner(opts); var editor = new Editor(); var curViewer = null; var selectedFile = null; var selectedDriveId = null; var selectedSiteId = null; var requestInProgress = false; var breadcrumb = []; var lastFolderArgs = null; var loadingPreviewFile = null; function getDrawioFileDoc(file, success, error) { if (file['@microsoft.graph.downloadUrl'] == null) { if (file.parentReference == null) { error(); } else { getODFileInfo(file.id, file.parentReference.driveId, function(completeFile) { getDrawioFileDoc(completeFile, success, error); }, error); return; } } var req = new XMLHttpRequest(); //TODO find another way to disable caching (adding a parameter breaks the url) req.open('GET', file['@microsoft.graph.downloadUrl']); var isPng = file.file? (file.file.mimeType == 'image/png') : false; req.onreadystatechange = function() { if (this.readyState == 4) { if (this.status >= 200 && this.status <= 299) { try { var cnt = req.responseText; if (isPng) { cnt = 'data:image/png;base64,' + Editor.base64Encode(cnt); cnt = Editor.extractGraphModelFromPng(cnt); } var doc = mxUtils.parseXml(cnt); var node = (doc.documentElement.nodeName == 'mxlibrary') ? doc.documentElement : Editor.extractGraphModel(doc.documentElement); if (node != null) { success(node.ownerDocument); return; } } catch(e) {} //on error and if the doc is null, the following line will call the error } error(); } }; if (isPng && req.overrideMimeType) { req.overrideMimeType('text/plain; charset=x-user-defined'); } req.send(); }; function doSubmit() { function submit(img) { pickedFileCallback(selectedFile, img); addToRecent(selectedFile); } if (withThumbnail && curViewer != null) { editor.exportToCanvas(function(canvas) { submit(EditorUi.prototype.createImageDataUri(canvas, null, 'png')); }, 400, null, null, function(err) { //TODO handle errors console.log(err); }, 600, null, null, null, null, null, curViewer); } else { submit(); } }; function renderFile(file) { if (prevDiv == null) { return; } prevDiv.style.background = 'transparent'; prevDiv.innerText = ''; function showRenderMsg(msg) { prevDiv.style.background = 'transparent'; prevDiv.innerText = ''; var status = document.createElement('div'); status.className = 'odPreviewStatus'; mxUtils.write(status, msg); prevDiv.appendChild(status); spinner.stop(); }; if (file == null || file.folder || /\.drawiolib$/.test(file.name)) { showRenderMsg(mxResources.get('noPreview')); return; } try { // Workaround for parentReference access if (file.remoteItem != null) { file = file.remoteItem; } loadingPreviewFile = file; spinner.spin(prevDiv); getDrawioFileDoc(file, function(doc) { spinner.stop(); if (loadingPreviewFile != file) { return; } else if (doc.documentElement.nodeName == 'mxlibrary') { showRenderMsg(mxResources.get('noPreview')); } else { var diagrams = doc.getElementsByTagName('diagram'); curViewer = AspectDialog.prototype.createViewer(prevDiv, diagrams.length == 0? doc.documentElement : diagrams[0], null, 'transparent'); } }, function() //If the file is not a draw.io diagram { selectedFile = null; showRenderMsg(mxResources.get('notADiagramFile')); }); } catch (e) { selectedFile = null; showRenderMsg(mxResources.get('notADiagramFile')); } }; function renderBreadcrumb() { var bcDiv = _$('.odFilesBreadcrumb'); if (bcDiv == null) return; bcDiv.innerText = ''; for (var i = 0; i < breadcrumb.length - 1; i++) { var folder = document.createElement('span'); folder.className = 'odBCFolder'; folder.innerHTML = mxUtils.htmlEntities(breadcrumb[i].name || mxResources.get('home')); bcDiv.appendChild(folder); (function(bcItem, index) { folder.addEventListener('click', function() { previewFn(null); breadcrumb = breadcrumb.slice(0, index); fillFolderFiles(bcItem.driveId, bcItem.folderId, bcItem.siteId, bcItem.name); }); })(breadcrumb[i], i); var sep = document.createElement('span'); sep.innerHTML = ' > '; bcDiv.appendChild(sep); } if (breadcrumb[breadcrumb.length - 1] != null) { var curr = document.createElement('span'); curr.innerHTML = mxUtils.htmlEntities((breadcrumb.length == 1) ? mxResources.get(foldersOnly ? 'selectFolder' : 'officeSelDiag') : (breadcrumb[breadcrumb.length - 1].name || mxResources.get('home'))); bcDiv.appendChild(curr); } }; function openFile() { if (selectedFile == null || requestInProgress) return; if (selectedDriveId == 'sharepoint') { fillFolderFiles('site', null, selectedFile.id, selectedFile.displayName); } else if (selectedDriveId == 'site') { fillFolderFiles('subsite', null, selectedFile.id, selectedFile.name); } else { var isFolder = selectedFile.folder; selectedFile = selectedFile.remoteItem? selectedFile.remoteItem : selectedFile; //handle remote items which is accessed indirectly var folderDI = (selectedFile.parentReference? selectedFile.parentReference.driveId : null) || selectedDriveId; var id = selectedFile.id; if (isFolder) { fillFolderFiles(folderDI, id, null, selectedFile.name); } else { doSubmit(); } } }; function fillFolderFiles(driveId, folderId, siteId, folderName, searchTxt) { if (requestInProgress) return; _$('.odCatsList').style.display = 'block'; _$('.odFilesSec').style.display = 'block'; // _$('#signOutLnk').style.display = ''; if (prevDiv != null) { prevDiv.innerText = ''; prevDiv.style.top = '50%'; } requestInProgress = true; var acceptRequest = true; var isSharepointSites = 0; lastFolderArgs = arguments; function renderList(potentialDrawioFiles) { spinner.stop(); var grid = document.createElement('table'); grid.className = 'odFileListGrid'; var currentItem = null; var count = 0; //TODO support paging for (var i = 0; potentialDrawioFiles!= null && i < potentialDrawioFiles.length; i++) { var item = potentialDrawioFiles[i]; if (isSharepointSites == 1 && item.webUrl && !(item.webUrl.indexOf('sharepoint.com/sites/') > 0 || item.webUrl.indexOf('sharepoint.com/') < 0)) { continue; } var title = item.displayName || item.name; var tooltip = mxUtils.htmlEntities(item.description || title); if (isSharepointSites) { item.folder = isSharepointSites == 2? {isRoot: true} : true; } var isFolder = item.folder != null; if (foldersOnly && !isFolder) { continue; } var row = document.createElement('tr'); row.className = (count++) % 2? 'odOddRow' : 'odEvenRow'; var td = document.createElement('td'); td.style.width = '36px'; var typeImg = document.createElement('img'); typeImg.src = '/images/' + (isFolder? 'folder.png' : 'file.png'); typeImg.className = 'odFileImg'; td.appendChild(typeImg); row.appendChild(td); td = document.createElement('td'); var titleDiv = document.createElement('div'); titleDiv.className = "odFileTitle"; titleDiv.innerHTML = mxUtils.htmlEntities(title); titleDiv.setAttribute('title', tooltip); td.appendChild(titleDiv); row.appendChild(td); grid.appendChild(row); if (currentItem == null) { currentItem = row; currentItem.className += ' odRowSelected'; selectedFile = item; selectedDriveId = driveId; if (!acceptAllFiles) { previewFn(selectedFile); } } (function(item2, row2) { row.addEventListener('dblclick', openFile); row.addEventListener('click', function() { if (currentItem != row2) { currentItem.className = currentItem.className.replace('odRowSelected', ''); currentItem = row2; currentItem.className += ' odRowSelected'; selectedFile = item2; selectedDriveId = driveId; if (!acceptAllFiles) { previewFn(selectedFile); } } }); })(item, row); } if (count == 0) { var emptyMsg = document.createElement('div'); emptyMsg.className = 'odEmptyFolder'; emptyMsg.innerHTML = mxUtils.htmlEntities(mxResources.get('folderEmpty', null, 'Folder is empty!')); filesList.appendChild(emptyMsg); } else { filesList.appendChild(grid); } renderBreadcrumb(); requestInProgress = false; }; var timeoutThread = setTimeout(function() { acceptRequest = false; requestInProgress = false; spinner.stop(); errorFn(mxResources.get('timeout')); }, 20000); //20 sec timeout var filesList = _$('.odFilesList'); filesList.innerText = ''; spinner.spin(filesList); var url; switch(driveId) { case 'recent': breadcrumb = [{name: mxResources.get('recent', null, 'Recent'), driveId: driveId}]; var recentList = getRecentList() || {}; var list = []; for (var id in recentList) { list.push(recentList[id]); } clearTimeout(timeoutThread); renderList(list); return; case 'shared': url = '/me/drive/sharedWithMe'; breadcrumb = [{name: mxResources.get('sharedWithMe', null, 'Shared With Me'), driveId: driveId}]; break; case 'sharepoint': url = '/sites?search='; breadcrumb = [{name: mxResources.get('sharepointSites', null, 'Sharepoint Sites'), driveId: driveId}]; isSharepointSites = 1; break; case 'site': breadcrumb.push({name: folderName, driveId: driveId, folderId: folderId, siteId: siteId}); url = '/sites/' + siteId + '/drives'; isSharepointSites = 2; break; case 'subsite': breadcrumb.push({name: folderName, driveId: driveId, folderId: folderId, siteId: siteId}); url = '/drives/' + siteId + (folderId? '/items/' + folderId : '/root') + '/children'; break; case 'search': //TODO search doesn't return any results, find out why then remove display: none from the searchBox driveId = selectedDriveId; breadcrumb = [{driveId: driveId, name: mxResources.get('back', null, 'Back')}]; searchTxt = encodeURIComponent(searchTxt.replace(/\'/g, '\\\'')); url = selectedSiteId? '/sites/' + selectedSiteId + '/drive/root/search(q=\'' + searchTxt + '\')' : (driveId? '/drives/' + driveId + '/root/search(q=\'' + searchTxt + '\')' : '/me/drive/root/search(q=\'' + searchTxt + '\')'); break; default: if (folderId == null) { breadcrumb = [{driveId: driveId}]; } else { breadcrumb.push({name: folderName, driveId: driveId, folderId: folderId}); } url = (driveId? '/drives/' + driveId : '/me/drive') + (folderId? '/items/' + folderId : '/root') + '/children'; } if (!isSharepointSites) { url += (url.indexOf('?') > 0 ? '&' : '?') + 'select=id,name,description,parentReference,file,createdBy,lastModifiedBy,lastModifiedDateTime,size,folder,remoteItem,@microsoft.graph.downloadUrl'; } var potentialDrawioFiles = []; function getChunk(nextUrl) { getODFilesList(nextUrl? nextUrl : url, function(resp) { if (!acceptRequest) return; var list = resp.value || []; if (acceptAllFiles || isSharepointSites) { Array.prototype.push.apply(potentialDrawioFiles, list); } else { for (var i = 0; i < list.length; i++) { var file = list[i]; var mimeType = file.file? file.file.mimeType : null; if (file.folder || mimeType == 'text/html' || mimeType == 'text/xml' || mimeType == 'application/xml' || mimeType == 'image/png' || /\.svg$/.test(file.name) || /\.html$/.test(file.name) || /\.xml$/.test(file.name) || /\.png$/.test(file.name) || /\.drawio$/.test(file.name) || /\.drawiolib$/.test(file.name)) { potentialDrawioFiles.push(file); } } } if (resp['@odata.nextLink'] && potentialDrawioFiles.length < 1000) // TODO Support dynamic paging instead of 1000 limit { getChunk(resp['@odata.nextLink']); } else { clearTimeout(timeoutThread); renderList(potentialDrawioFiles); } }, function(err) { if (!acceptRequest) return; clearTimeout(timeoutThread); var errMsg = null; try { errMsg = JSON.parse(err.responseText).error.message; } catch(e){} //ignore errors errorFn(mxResources.get('errorFetchingFolder', null, 'Error fetching folder items') + (errMsg != null? ' (' + errMsg + ')' : '')); requestInProgress = false; spinner.stop(); }, nextUrl != null); }; getChunk(); }; this.getSelectedItem = function() { if (selectedFile != null) { addToRecent(selectedFile); } return selectedFile; } //Code execution starts here if (_$('#mxODPickerCss') == null) { var head = document.head || document.getElementsByTagName('head')[0], style = document.createElement('style'); head.appendChild(style); style.type = 'text/css'; style.id = 'mxODPickerCss'; style.appendChild(document.createTextNode(css)); } container.innerHTML = html; var prevDiv = _$('.odPreview'); var selectedCat = _$('#odFiles'); var cats = _$$('.odCatListTitle'); function setSelectedCat(cat) { selectedCat.className = selectedCat.className.replace('odCatSelected', ''); selectedCat = cat; selectedCat.className += ' odCatSelected'; }; for (var i = 0; i < cats.length; i++) { cats[i].addEventListener('click', function() { loadingPreviewFile = null; selectedFile = null; if (requestInProgress) return; setSelectedCat(this); switch(this.id) { case 'odFiles': fillFolderFiles(); break; case 'odRecent': fillFolderFiles('recent'); break; case 'odShared': fillFolderFiles('shared'); break; case 'odSharepoint': fillFolderFiles('sharepoint'); break; } }); } //Search (Currently API doesn't work) var delayTimer = null; function doSearch(searchStr) { if (requestInProgress) return; delayTimer = null; fillFolderFiles('search', null, null, null, searchStr) }; //Use keyup to detect delete and backspace _$('#odSearchBox').addEventListener('keyup', function(evt) { var searchInput = this; if (delayTimer != null) { clearTimeout(delayTimer); } if (evt.keyCode == 13) { doSearch(searchInput.value); } else { delayTimer = setTimeout(function() { doSearch(searchInput.value); }, 500); } }); function refreshFolder() { if (lastFolderArgs != null) { previewFn(null); fillFolderFiles.apply(this, lastFolderArgs); } }; _$('#refreshOD').addEventListener('click', refreshFolder); if (backFn) { _$('#odBackBtn').addEventListener('click', backFn); } if (withSubmitBtn) { _$('#odSubmitBtn').addEventListener('click', doSubmit); } if (initFolderPath != null) { var folderInfo = initFolderPath.pop(); if (initFolderPath[0].driveId == 'sharepoint') { setSelectedCat(_$('#odSharepoint')); } breadcrumb = initFolderPath; fillFolderFiles(folderInfo.driveId, folderInfo.folderId, folderInfo.siteId, folderInfo.name); } else { fillFolderFiles(); } };