diff --git a/package.json b/package.json index 76a062e4..f38eb7bf 100644 --- a/package.json +++ b/package.json @@ -12,12 +12,10 @@ "ejs": "~0.8.4" }, "devDependencies": { - "grunt": "~0.4.1", "grunt-contrib-requirejs": "~0.4.1", "grunt-contrib-less": "~0.7.0", "grunt-string-replace": "~0.2.4", "grunt-contrib-copy": "~0.4.1", - "bower": "~1.2.5", "grunt-bower-requirejs": "~0.7.1", "grunt-bower-task": "~0.3.1", "grunt-bump": "0.0.11", diff --git a/public/res/classes/FileDescriptor.js b/public/res/classes/FileDescriptor.js index d8d16357..ff84e700 100644 --- a/public/res/classes/FileDescriptor.js +++ b/public/res/classes/FileDescriptor.js @@ -106,7 +106,6 @@ define([ FileDescriptor.prototype.removeSyncLocation = function(syncAttributes) { utils.removeIndexFromArray(this.fileIndex + ".sync", syncAttributes.syncIndex); delete this.syncLocations[syncAttributes.syncIndex]; - storage.removeItem(syncAttributes.syncIndex); }; FileDescriptor.prototype.addPublishLocation = function(publishAttributes) { @@ -118,7 +117,6 @@ define([ FileDescriptor.prototype.removePublishLocation = function(publishAttributes) { utils.removeIndexFromArray(this.fileIndex + ".publish", publishAttributes.publishIndex); delete this.publishLocations[publishAttributes.publishIndex]; - storage.removeItem(publishAttributes.publishIndex); }; FileDescriptor.prototype.composeTitle = function() { diff --git a/public/res/classes/Provider.js b/public/res/classes/Provider.js index f52ea357..890a7f29 100644 --- a/public/res/classes/Provider.js +++ b/public/res/classes/Provider.js @@ -49,15 +49,25 @@ define([ return content; }; - Provider.prototype.parseSerializedContent = function(content) { + Provider.prototype.parseContent = function(content) { + if(!_.isString(content)) { + // Real time content is already an object + return { + content: content.content, + discussionList: content.discussionList, + discussionListJSON: JSON.stringify(content.discussionList) + }; + } + var discussionList; var discussionListJSON = '{}'; var discussionExtractor = /$/.exec(content); - if(discussionExtractor && this.parseDiscussionList(discussionExtractor[1])) { + if(discussionExtractor && (discussionList = this.parseDiscussionList(discussionExtractor[1]))) { content = content.substring(0, discussionExtractor.index); discussionListJSON = discussionExtractor[1]; } return { content: content, + discussionList: discussionList || {}, discussionListJSON: discussionListJSON }; }; diff --git a/public/res/extensions/comments.js b/public/res/extensions/comments.js index 20591bbe..5625a02a 100644 --- a/public/res/extensions/comments.js +++ b/public/res/extensions/comments.js @@ -376,7 +376,7 @@ define([ // Create discussion index var discussionIndex; do { - discussionIndex = utils.randomString() + utils.randomString(); // Increased size to prevent collision + discussionIndex = utils.randomString(); } while(_.has(discussionList, discussionIndex)); discussion.discussionIndex = discussionIndex; discussionList[discussionIndex] = discussion; diff --git a/public/res/extensions/dialogManagePublication.js b/public/res/extensions/dialogManagePublication.js index 973aedae..9377f51a 100644 --- a/public/res/extensions/dialogManagePublication.js +++ b/public/res/extensions/dialogManagePublication.js @@ -21,7 +21,7 @@ define([ } $showAlreadyPublishedElt.toggleClass("hide", _.size(fileDesc.publishLocations) === 0); - + var publishListHtml = _.reduce(fileDesc.publishLocations, function(result, publishAttributes) { var formattedAttributes = _.omit(publishAttributes, "provider", "publishIndex", "sharingLink"); formattedAttributes.password && (formattedAttributes.password = "********"); @@ -32,7 +32,7 @@ define([ }); }, ''); publishListElt.innerHTML = publishListHtml; - + _.each(publishListElt.querySelectorAll('.remove-button'), function(removeButtonElt) { var $removeButtonElt = $(removeButtonElt); var publishAttributes = fileDesc.publishLocations[$removeButtonElt.data('publishIndex')]; @@ -59,4 +59,4 @@ define([ }; return dialogManagePublication; -}); \ No newline at end of file +}); diff --git a/public/res/extensions/documentManager.js b/public/res/extensions/documentManager.js index 0c21056e..8b002ed4 100644 --- a/public/res/extensions/documentManager.js +++ b/public/res/extensions/documentManager.js @@ -106,8 +106,6 @@ define([ // Delete folders _.each(selectedFolderList, function(folderDesc) { utils.removeIndexFromArray("folder.list", folderDesc.folderIndex); - storage.removeItem(folderDesc.folderIndex + ".name"); - storage.removeItem(folderDesc.folderIndex + ".files"); delete folderList[folderDesc.folderIndex]; }); eventMgr.onFoldersChanged(); @@ -281,9 +279,9 @@ define([ // Set checkbox event listeners $(documentListElt.querySelectorAll('[type=checkbox]')).change(doActiveButtons); - + }, 50); - + documentManager.onFileCreated = refreshManager; documentManager.onFileDeleted = refreshManager; documentManager.onSyncExportSuccess = refreshManager; @@ -429,4 +427,4 @@ define([ return documentManager; -}); \ No newline at end of file +}); diff --git a/public/res/fileMgr.js b/public/res/fileMgr.js index 767ec863..6126c3f1 100644 --- a/public/res/fileMgr.js +++ b/public/res/fileMgr.js @@ -110,6 +110,8 @@ define([ utils.removeIndexFromArray("file.list", fileDesc.fileIndex); delete fileSystem[fileDesc.fileIndex]; + // Don't bother with fields in localStorage, they will be removed on next page load + if(fileMgr.currentFile === fileDesc) { // Unset the current fileDesc fileMgr.currentFile = undefined; @@ -117,27 +119,6 @@ define([ fileMgr.selectFile(); } - // Remove synchronized locations from storage - _.each(fileDesc.syncLocations, function(syncAttributes) { - storage.removeItem(syncAttributes.syncIndex); - }); - - // Remove publish locations from storage - _.each(fileDesc.publishLocations, function(publishAttributes) { - storage.removeItem(publishAttributes.publishIndex); - }); - - storage.removeItem(fileDesc.fileIndex + ".title"); - storage.removeItem(fileDesc.fileIndex + ".content"); - storage.removeItem(fileDesc.fileIndex + ".sync"); - storage.removeItem(fileDesc.fileIndex + ".publish"); - storage.removeItem(fileDesc.fileIndex + ".selectTime"); - storage.removeItem(fileDesc.fileIndex + ".editorStart"); - storage.removeItem(fileDesc.fileIndex + ".editorEnd"); - storage.removeItem(fileDesc.fileIndex + ".editorScrollTop"); - storage.removeItem(fileDesc.fileIndex + ".previewScrollTop"); - storage.removeItem(fileDesc.fileIndex + ".discussionList"); - eventMgr.onFileDeleted(fileDesc); }; @@ -148,12 +129,6 @@ define([ }); }; - // Get syncAttributes from syncIndex - fileMgr.getSyncAttributes = function(syncIndex) { - var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); - return fileDesc && fileDesc.syncLocations[syncIndex]; - }; - // Get the file descriptor associated to a publishIndex fileMgr.getFileFromPublishIndex = function(publishIndex) { return _.find(fileSystem, function(fileDesc) { diff --git a/public/res/fileSystem.js b/public/res/fileSystem.js index 68042d36..17840e94 100644 --- a/public/res/fileSystem.js +++ b/public/res/fileSystem.js @@ -3,13 +3,21 @@ define([ "utils", "classes/FileDescriptor", "storage", -], function(_, utils, FileDescriptor) { +], function(_, utils, FileDescriptor, storage) { var fileSystem = {}; // Retrieve file descriptors from localStorage - _.each(utils.retrieveIndexArray("file.list"), function(fileIndex) { + utils.retrieveIndexArray("file.list").forEach(function(fileIndex) { fileSystem[fileIndex] = new FileDescriptor(fileIndex); }); + // Clean fields from deleted files in local storage + Object.keys(storage).forEach(function(key) { + var match = key.match(/(file\.\S+?)\.\S+/); + if(match && !fileSystem.hasOwnProperty(match[1])) { + storage.removeItem(key); + } + }); + return fileSystem; -}); \ No newline at end of file +}); diff --git a/public/res/folderList.js b/public/res/folderList.js index 59d352c1..f9b059e7 100644 --- a/public/res/folderList.js +++ b/public/res/folderList.js @@ -1,15 +1,24 @@ define([ "underscore", "utils", + "storage", "classes/FolderDescriptor", "storage", -], function(_, utils, FolderDescriptor) { +], function(_, utils, storage, FolderDescriptor) { var folderList = {}; // Retrieve folder descriptors from localStorage - _.each(utils.retrieveIndexArray("folder.list"), function(folderIndex) { + utils.retrieveIndexArray("folder.list").forEach(function(folderIndex) { folderList[folderIndex] = new FolderDescriptor(folderIndex); }); + // Clean fields from deleted folders in local storage + Object.keys(storage).forEach(function(key) { + var match = key.match(/(folder\.\S+?)\.\S+/); + if(match && !folderList.hasOwnProperty(match[1])) { + storage.removeItem(key); + } + }); + return folderList; -}); \ No newline at end of file +}); diff --git a/public/res/helpers/googleHelper.js b/public/res/helpers/googleHelper.js index a5c30096..5d337b03 100644 --- a/public/res/helpers/googleHelper.js +++ b/public/res/helpers/googleHelper.js @@ -542,13 +542,11 @@ define([ task.chain(recursiveDownloadContent); return; } + var url = file.downloadUrl; // if file is a real time document if(file.mimeType.indexOf("application/vnd.google-apps.drive-sdk") === 0) { - file.content = ""; file.isRealtime = true; - objects.shift(); - task.chain(recursiveDownloadContent); - return; + url = 'https://www.googleapis.com/drive/v2/files/' + file.id + '/realtime'; } var headers = {}; var authorizationMgr = authorizationMgrMap[accountId]; @@ -556,12 +554,12 @@ define([ headers.Authorization = "Bearer " + authorizationMgr.token.access_token; } $.ajax({ - url: file.downloadUrl, + url: url, headers: headers, data: { key: constants.GOOGLE_API_KEY }, - dataType: "text", + dataType: file.isRealtime ? 'json' : 'text', timeout: constants.AJAX_TIMEOUT }).done(function(data) { file.content = data; diff --git a/public/res/main.js b/public/res/main.js index 12f5162d..d989d80e 100644 --- a/public/res/main.js +++ b/public/res/main.js @@ -43,7 +43,7 @@ requirejs.config({ 'bootstrap-tour': 'bower-libs/bootstrap-tour/build/js/bootstrap-tour', css_browser_selector: 'bower-libs/css_browser_selector/css_browser_selector', 'pagedown-extra': 'bower-libs/pagedown-extra/Markdown.Extra', - pagedown: 'bower-libs/stackedit-pagedown/Markdown.Editor', + pagedown: 'libs/Markdown.Editor', 'require-css': 'bower-libs/require-css/css', xregexp: 'bower-libs/xregexp/xregexp-all', yaml: 'bower-libs/yaml.js', @@ -161,10 +161,10 @@ requirejs.config({ 'jquery' ], pagedown: [ - 'bower-libs/stackedit-pagedown/Markdown.Converter' + 'libs/Markdown.Converter' ], 'pagedown-extra': [ - 'bower-libs/stackedit-pagedown/Markdown.Converter' + 'libs/Markdown.Converter' ] } }); diff --git a/public/res/providers/dropboxProvider.js b/public/res/providers/dropboxProvider.js index f25d8c2e..412093e6 100644 --- a/public/res/providers/dropboxProvider.js +++ b/public/res/providers/dropboxProvider.js @@ -61,7 +61,7 @@ define([ } var fileDescList = []; _.each(result, function(file) { - var parsedContent = dropboxProvider.parseSerializedContent(file.content); + var parsedContent = dropboxProvider.parseContent(file.content); var syncAttributes = createSyncAttributes(file.path, file.versionTag, parsedContent.content, parsedContent.discussionListJSON); var syncLocations = {}; syncLocations[syncAttributes.syncIndex] = syncAttributes; @@ -152,11 +152,13 @@ define([ var interestingChanges = []; _.each(changes, function(change) { var syncIndex = createSyncIndex(change.path); - var syncAttributes = fileMgr.getSyncAttributes(syncIndex); - if(syncAttributes === undefined) { + var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); + var syncAttributes = fileDesc && fileDesc.syncLocations[syncIndex]; + if(!syncAttributes) { return; } - // Store syncAttributes to avoid 2 times searching + // Store fileDesc and syncAttributes references to avoid 2 times search + change.fileDesc = fileDesc; change.syncAttributes = syncAttributes; // Delete if(change.wasRemoved === true) { @@ -179,13 +181,8 @@ define([ return callback(); } var change = changes.pop(); + var fileDesc = change.fileDesc; var syncAttributes = change.syncAttributes; - var syncIndex = syncAttributes.syncIndex; - var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); - // No file corresponding (file may have been deleted locally) - if(fileDesc === undefined) { - return; - } // File deleted if(change.wasRemoved === true) { eventMgr.onError('"' + fileDesc.title + '" has been removed from Dropbox.'); @@ -193,10 +190,10 @@ define([ return eventMgr.onSyncRemoved(fileDesc, syncAttributes); } var file = change.stat; - var parsedContent = dropboxProvider.parseSerializedContent(file.content); + var parsedContent = dropboxProvider.parseContent(file.content); var remoteContent = parsedContent.content; var remoteDiscussionListJSON = parsedContent.discussionListJSON; - var remoteDiscussionList = JSON.parse(remoteDiscussionListJSON); + var remoteDiscussionList = parsedContent.discussionList; var remoteCRC = dropboxProvider.syncMerge(fileDesc, syncAttributes, remoteContent, fileDesc.title, remoteDiscussionList, remoteDiscussionListJSON); // Update syncAttributes syncAttributes.version = file.versionTag; diff --git a/public/res/providers/gdriveProviderBuilder.js b/public/res/providers/gdriveProviderBuilder.js index 45f1990e..4d9718e6 100644 --- a/public/res/providers/gdriveProviderBuilder.js +++ b/public/res/providers/gdriveProviderBuilder.js @@ -62,7 +62,7 @@ define([ var fileDescList = []; var fileDesc; _.each(result, function(file) { - var parsedContent = gdriveProvider.parseSerializedContent(file.content); + var parsedContent = gdriveProvider.parseContent(file.content); var syncAttributes = createSyncAttributes(file.id, file.etag, parsedContent.content, file.title, parsedContent.discussionListJSON); syncAttributes.isRealtime = file.isRealtime; var syncLocations = {}; @@ -188,11 +188,13 @@ define([ var interestingChanges = []; _.each(changes, function(change) { var syncIndex = createSyncIndex(change.fileId); - var syncAttributes = fileMgr.getSyncAttributes(syncIndex); - if(syncAttributes === undefined) { + var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); + var syncAttributes = fileDesc && fileDesc.syncLocations[syncIndex]; + if(!syncAttributes) { return; } - // Store syncAttributes to avoid 2 times searching + // Store fileDesc and syncAttributes references to avoid 2 times search + change.fileDesc = fileDesc; change.syncAttributes = syncAttributes; // Delete if(change.deleted === true) { @@ -215,13 +217,8 @@ define([ return callback(); } var change = changes.pop(); + var fileDesc = change.fileDesc; var syncAttributes = change.syncAttributes; - var syncIndex = syncAttributes.syncIndex; - var fileDesc = fileMgr.getFileFromSyncIndex(syncIndex); - // No file corresponding (file may have been deleted locally) - if(fileDesc === undefined) { - return; - } // File deleted if(change.deleted === true) { eventMgr.onError('"' + fileDesc.title + '" has been removed from ' + providerName + '.'); @@ -233,11 +230,11 @@ define([ return; } var file = change.file; - var parsedContent = gdriveProvider.parseSerializedContent(file.content); + var parsedContent = gdriveProvider.parseContent(file.content); var remoteContent = parsedContent.content; var remoteTitle = file.title; var remoteDiscussionListJSON = parsedContent.discussionListJSON; - var remoteDiscussionList = JSON.parse(remoteDiscussionListJSON); + var remoteDiscussionList = parsedContent.discussionList; var remoteCRC = gdriveProvider.syncMerge(fileDesc, syncAttributes, remoteContent, remoteTitle, remoteDiscussionList, remoteDiscussionListJSON); // Update syncAttributes @@ -291,8 +288,8 @@ define([ }); // Realtime closure + var realtimeContext; (function() { - var realtimeContext; function toRealtimeDiscussion(context, discussion) { var realtimeCommentList = context.model.createList(); @@ -430,7 +427,7 @@ define([ } } - function updateCRCs() { + function updateStatus() { var context = realtimeContext; if(!context) { return; @@ -487,7 +484,7 @@ define([ // For local changes, CRCs are updated on "save success" event if(context.isServerChange) { - updateCRCs(); + updateStatus(); } else { context.model.endCompoundOperation(); @@ -570,7 +567,7 @@ define([ // Also listen to "save success" event doc.addEventListener(gapi.drive.realtime.EventType.DOCUMENT_SAVE_STATE_CHANGED, function(evt) { if(evt.isPending === false && evt.isSaving === false) { - updateCRCs(); + updateStatus(); } }); diff --git a/public/res/publisher.js b/public/res/publisher.js index e22fe084..c98f5aad 100644 --- a/public/res/publisher.js +++ b/public/res/publisher.js @@ -35,29 +35,40 @@ define([ }).compact().object().value(); // Retrieve publish locations from storage - _.each(fileSystem, function(fileDesc) { - _.each(utils.retrieveIndexArray(fileDesc.fileIndex + ".publish"), function(publishIndex) { - try { - var publishAttributes = JSON.parse(storage[publishIndex]); - // Store publishIndex - publishAttributes.publishIndex = publishIndex; - // Replace provider ID by provider module in attributes - var provider = providerMap[publishAttributes.provider]; - if(!provider) { - throw new Error("Invalid provider ID: " + publishAttributes.provider); + (function() { + var publishIndexMap = {}; + _.each(fileSystem, function(fileDesc) { + utils.retrieveIndexArray(fileDesc.fileIndex + ".publish").forEach(function(publishIndex) { + try { + var publishAttributes = JSON.parse(storage[publishIndex]); + // Store publishIndex + publishAttributes.publishIndex = publishIndex; + // Replace provider ID by provider module in attributes + var provider = providerMap[publishAttributes.provider]; + if(!provider) { + throw new Error("Invalid provider ID: " + publishAttributes.provider); + } + publishAttributes.provider = provider; + fileDesc.publishLocations[publishIndex] = publishAttributes; + publishIndexMap[publishIndex] = publishAttributes; } - publishAttributes.provider = provider; - fileDesc.publishLocations[publishIndex] = publishAttributes; - } - catch(e) { - // storage can be corrupted - eventMgr.onError(e); - // Remove publish location - utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishIndex); - storage.removeItem(publishIndex); + catch(e) { + // storage can be corrupted + eventMgr.onError(e); + // Remove publish location + utils.removeIndexFromArray(fileDesc.fileIndex + ".publish", publishIndex); + } + }); + }); + + // Clean fields from deleted files in local storage + Object.keys(storage).forEach(function(key) { + var match = key.match(/(publish\.\S+?)\.\S+/); + if(match && !publishIndexMap.hasOwnProperty(match[1])) { + storage.removeItem(key); } }); - }); + })(); // Apply template to the current document publisher.applyTemplate = function(fileDesc, publishAttributes, html) { @@ -286,7 +297,7 @@ define([ }); } - // + // $(".action-process-publish").click(performNewLocation); $(".action-update-publication").click(publisher.publish); @@ -364,4 +375,4 @@ define([ eventMgr.onPublisherCreated(publisher); return publisher; -}); \ No newline at end of file +}); diff --git a/public/res/storage.js b/public/res/storage.js index 7261ed5d..4dc49659 100644 --- a/public/res/storage.js +++ b/public/res/storage.js @@ -134,29 +134,7 @@ define([ version = "v7"; } - if(version == "v7") { - _.each(_.keys(localStorage), function(key) { - var matchResult = key.match(/(file\.\S+\.)\S+/); - if(matchResult) { - if(!_.has(localStorage, matchResult[1] + 'title')) { - localStorage.removeItem(key); - } - } - }); - version = "v8"; - } - - if(version == "v8") { - _.each(_.keys(localStorage), function(key) { - var matchResult = key.match(/file\.\S+\.(editorEnd|editorStart)/); - if(matchResult) { - localStorage.removeItem(key); - } - }); - version = "v9"; - } - - if(version == "v9") { + if(version == "v7" || version == "v8" || version == "v9") { if(_.has(localStorage, 'settings')) { settings = JSON.parse(localStorage.settings); delete settings.editorFontFamily; @@ -235,26 +213,9 @@ define([ version = "v16"; } - if(version == "v16") { - _.each(_.keys(localStorage), function(key) { - var matchResult = key.match(/(file\.\S+\.)\S+/); - if(matchResult) { - if(!_.has(localStorage, matchResult[1] + 'title')) { - localStorage.removeItem(key); - } - } - }); - version = "v17"; - } - - if(version == "v17") { + if(version == "v16" || version == "v17") { localStorage.removeItem('focusMode'); localStorage.removeItem('mode'); - _.each(_.keys(localStorage), function(key) { - if(key.match(/file\.\S+\.editorSelectRange/)) { - localStorage.removeItem(key); - } - }); version = "v18"; } diff --git a/public/res/synchronizer.js b/public/res/synchronizer.js index 6b767fc0..98301abb 100644 --- a/public/res/synchronizer.js +++ b/public/res/synchronizer.js @@ -24,29 +24,40 @@ define([ }).compact().object().value(); // Retrieve sync locations from storage - _.each(fileSystem, function(fileDesc) { - _.each(utils.retrieveIndexArray(fileDesc.fileIndex + ".sync"), function(syncIndex) { - try { - var syncAttributes = JSON.parse(storage[syncIndex]); - // Store syncIndex - syncAttributes.syncIndex = syncIndex; - // Replace provider ID by provider module in attributes - var provider = providerMap[syncAttributes.provider]; - if(!provider) { - throw new Error("Invalid provider ID: " + syncAttributes.provider); + (function() { + var syncIndexMap = {}; + _.each(fileSystem, function(fileDesc) { + utils.retrieveIndexArray(fileDesc.fileIndex + ".sync").forEach(function(syncIndex) { + try { + var syncAttributes = JSON.parse(storage[syncIndex]); + // Store syncIndex + syncAttributes.syncIndex = syncIndex; + // Replace provider ID by provider module in attributes + var provider = providerMap[syncAttributes.provider]; + if(!provider) { + throw new Error("Invalid provider ID: " + syncAttributes.provider); + } + syncAttributes.provider = provider; + fileDesc.syncLocations[syncIndex] = syncAttributes; + syncIndexMap[syncIndex] = syncAttributes; } - syncAttributes.provider = provider; - fileDesc.syncLocations[syncIndex] = syncAttributes; - } - catch(e) { - // storage can be corrupted - eventMgr.onError(e); - // Remove sync location - utils.removeIndexFromArray(fileDesc.fileIndex + ".sync", syncIndex); - storage.removeItem(syncIndex); + catch(e) { + // storage can be corrupted + eventMgr.onError(e); + // Remove sync location + utils.removeIndexFromArray(fileDesc.fileIndex + ".sync", syncIndex); + } + }); + }); + + // Clean fields from deleted files in local storage + Object.keys(storage).forEach(function(key) { + var match = key.match(/(sync\.\S+?)\.\S+/); + if(match && !syncIndexMap.hasOwnProperty(match[1])) { + storage.removeItem(key); } }); - }); + })(); // AutoSync configuration _.each(providerMap, function(provider) { diff --git a/public/res/utils.js b/public/res/utils.js index b7b3d4bd..945a65ba 100644 --- a/public/res/utils.js +++ b/public/res/utils.js @@ -44,6 +44,18 @@ define([ }; }; + // Generates a 24 chars length random string (should be enough to prevent collisions) + utils.randomString = (function() { + var max = Math.pow(36, 6); + function s6() { + // Linear [0-9a-z]{6} random string + return ('000000' + (Math.random() * max | 0).toString(36)).slice(-6); + } + return function() { + return [s6(), s6(), s6(), s6()].join(''); + }; + })(); + // Return a parameter from the URL utils.getURLParameter = function(name) { // Parameter can be either a search parameter (&name=...) or a hash fragment parameter (#!name=...) @@ -326,14 +338,9 @@ define([ } }; - // Generates a random string - utils.randomString = function() { - return _.random(4294967296).toString(36); - }; - // Time shared by others modules utils.updateCurrentTime = function() { - utils.currentTime = new Date().getTime(); + utils.currentTime = Date.now(); }; utils.updateCurrentTime();