From 3c31988e9ab808f36e8ae6105266c5effcb11ad0 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Fri, 10 Jun 2016 16:06:02 +0100 Subject: [PATCH 01/20] enable on-demand viewing of pdfs for per-user compiles --- .../coffee/ide/pdfng/directives/pdfRenderer.coffee | 3 ++- .../coffee/ide/pdfng/directives/pdfViewer.coffee | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee index 5639d670f0..e634afea3a 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfRenderer.coffee @@ -12,7 +12,8 @@ define [ constructor: (@url, @options) -> # PDFJS.disableFontFace = true # avoids repaints, uses worker more - # PDFJS.disableAutoFetch = true # enable this to prevent loading whole file + if @options.disableAutoFetch + PDFJS.disableAutoFetch = true # prevent loading whole file # PDFJS.disableStream # PDFJS.disableRange @scale = @options.scale || 1 diff --git a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee index f0ec8d61b1..4b6209717c 100644 --- a/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee +++ b/services/web/public/coffee/ide/pdfng/directives/pdfViewer.coffee @@ -27,13 +27,21 @@ define [ $scope.document.destroy() if $scope.document? $scope.loadCount = if $scope.loadCount? then $scope.loadCount + 1 else 1 # TODO need a proper url manipulation library to add to query string - $scope.document = new PDFRenderer($scope.pdfSrc + '&pdfng=true' , { + url = $scope.pdfSrc + # add 'pdfng=true' to show that we are using the angular pdfjs viewer + queryStringExists = url.match(/\?/) + url = url + (if not queryStringExists then '?' else '&') + 'pdfng=true' + # for isolated compiles, load the pdf on-demand because nobody will overwrite it + onDemandLoading = window.location?.search?.match(/isolated=true/)? + $scope.document = new PDFRenderer(url, { scale: 1, + disableAutoFetch: if onDemandLoading then true else undefined navigateFn: (ref) -> # this function captures clicks on the annotation links $scope.navigateTo = ref $scope.$apply() progressCallback: (progress) -> + return if onDemandLoading is true # don't show progress for on-demand page loading $scope.$emit 'progress', progress loadedCallback: () -> $scope.$emit 'loaded' From 88fb9558843446199c3bafa16755f146071ca357 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 28 Jun 2016 16:07:11 +0100 Subject: [PATCH 02/20] hook notifications handler up to make request which doesn't make request if url not set --- .../Features/Notifications/NotificationsHandler.coffee | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/web/app/coffee/Features/Notifications/NotificationsHandler.coffee b/services/web/app/coffee/Features/Notifications/NotificationsHandler.coffee index d3e2cb3cb9..a7cf6a4672 100644 --- a/services/web/app/coffee/Features/Notifications/NotificationsHandler.coffee +++ b/services/web/app/coffee/Features/Notifications/NotificationsHandler.coffee @@ -6,7 +6,7 @@ oneSecond = 1000 makeRequest = (opts, callback)-> if !settings.apis.notifications?.url? - return callback() + return callback(null, statusCode:200) else request(opts, callback) @@ -18,7 +18,7 @@ module.exports = json: true timeout: oneSecond method: "GET" - request opts, (err, res, unreadNotifications)-> + makeRequest opts, (err, res, unreadNotifications)-> statusCode = if res? then res.statusCode else 500 if err? or statusCode != 200 e = new Error("something went wrong getting notifications, #{err}, #{statusCode}") @@ -40,7 +40,7 @@ module.exports = templateKey:templateKey } logger.log opts:opts, "creating notification for user" - request opts, callback + makeRequest opts, callback markAsReadWithKey: (user_id, key, callback)-> opts = @@ -51,7 +51,7 @@ module.exports = key:key } logger.log user_id:user_id, key:key, "sending mark notification as read with key to notifications api" - request opts, callback + makeRequest opts, callback markAsRead: (user_id, notification_id, callback)-> @@ -60,4 +60,4 @@ module.exports = uri: "#{settings.apis.notifications?.url}/user/#{user_id}/notification/#{notification_id}" timeout:oneSecond logger.log user_id:user_id, notification_id:notification_id, "sending mark notification as read to notifications api" - request opts, callback + makeRequest opts, callback From 8f14526354c904531a4a2aaf3ac5c6205695f493 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Tue, 28 Jun 2016 17:07:27 +0100 Subject: [PATCH 03/20] added custom footer in email option --- services/web/app/coffee/Features/Email/EmailBuilder.coffee | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/services/web/app/coffee/Features/Email/EmailBuilder.coffee b/services/web/app/coffee/Features/Email/EmailBuilder.coffee index e14b9e4582..4bcf0c671d 100644 --- a/services/web/app/coffee/Features/Email/EmailBuilder.coffee +++ b/services/web/app/coffee/Features/Email/EmailBuilder.coffee @@ -3,6 +3,8 @@ PersonalEmailLayout = require("./Layouts/PersonalEmailLayout") NotificationEmailLayout = require("./Layouts/NotificationEmailLayout") settings = require("settings-sharelatex") + + templates = {} templates.registered = @@ -114,6 +116,8 @@ module.exports = template = templates[templateName] opts.siteUrl = settings.siteUrl opts.body = template.compiledTemplate(opts) + if settings.email?.templates?.customFooter? + opts.body += settings.email?.templates?.customFooter return { subject : template.subject(opts) html: template.layout(opts) From 5ad0c06770803c99f8d9e7e8db1eed16fe8f06f6 Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Tue, 28 Jun 2016 17:19:02 +0100 Subject: [PATCH 04/20] Regex now matches new folder nomenclature. --- .../web/public/coffee/ide/pdf/controllers/PdfController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index 610915ec3a..ab85755c36 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -237,7 +237,7 @@ define [ return null normalizeFilePath = (path) -> - path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}\/(\.\/)?/, "") + path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}-[0-9a-f]{24}\/(\.\/)?/, "") path = path.replace(/^\/compile\//, "") rootDocDirname = ide.fileTreeManager.getRootDocDirname() From d037cb93a9f0a3330ffe28f7c56902fdcd49167d Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Wed, 29 Jun 2016 10:42:51 +0100 Subject: [PATCH 05/20] Wiki styles clean-up. --- services/web/public/stylesheets/app/wiki.less | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/services/web/public/stylesheets/app/wiki.less b/services/web/public/stylesheets/app/wiki.less index 2bc962961f..5f7462d02c 100644 --- a/services/web/public/stylesheets/app/wiki.less +++ b/services/web/public/stylesheets/app/wiki.less @@ -41,11 +41,6 @@ .example { max-width: 100%; - & > div { - display: block !important; - width: auto !important; - } - .code { pre { background-color: @gray-lightest; @@ -60,9 +55,9 @@ padding-top: 10px; img { - width: auto !important; - height: auto !important; - max-width: 100% !important; + width: auto; + height: auto; + max-width: 100%; box-shadow: 0 1px 3px @gray-light; border-radius: 6px; } From 36e09e3b0c6324505ad56f255b8926b182b645fc Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Wed, 29 Jun 2016 14:19:16 +0100 Subject: [PATCH 06/20] Make the user id portion of the path optional. --- .../web/public/coffee/ide/pdf/controllers/PdfController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index ab85755c36..b9b8d234dd 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -237,7 +237,7 @@ define [ return null normalizeFilePath = (path) -> - path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}-[0-9a-f]{24}\/(\.\/)?/, "") + path = path.replace(/^(.*)\/compiles\/[0-9a-f]{24}(-[0-9a-f]{24})?\/(\.\/)?/, "") path = path.replace(/^\/compile\//, "") rootDocDirname = ide.fileTreeManager.getRootDocDirname() From 000c862ae1882c974714a435fc8ca013b5493a3b Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Wed, 29 Jun 2016 15:36:33 +0100 Subject: [PATCH 07/20] return 404 if blog returns 403, caused by file not existing --- services/web/app/coffee/Features/Blog/BlogController.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/app/coffee/Features/Blog/BlogController.coffee b/services/web/app/coffee/Features/Blog/BlogController.coffee index 8f726602c3..11af432624 100644 --- a/services/web/app/coffee/Features/Blog/BlogController.coffee +++ b/services/web/app/coffee/Features/Blog/BlogController.coffee @@ -20,7 +20,7 @@ module.exports = BlogController = logger.log url:url, "proxying request to blog api" request.get blogUrl, (err, r, data)-> - if r?.statusCode == 404 + if r?.statusCode == 404 or r?.statusCode == 403 return ErrorController.notFound(req, res, next) if err? return res.send 500 From c5f53ef4317794423c2eaa736e65e739d3411885 Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Thu, 30 Jun 2016 11:30:30 +0100 Subject: [PATCH 08/20] Track log hints feedback. --- services/web/app/views/project/editor/pdf.jade | 4 ++-- .../public/coffee/ide/pdf/controllers/PdfController.coffee | 7 +++++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/project/editor/pdf.jade b/services/web/app/views/project/editor/pdf.jade index 091831a22d..3bc459f290 100644 --- a/services/web/app/views/project/editor/pdf.jade +++ b/services/web/app/views/project/editor/pdf.jade @@ -128,12 +128,12 @@ div.full-size.pdf(ng-controller="PdfController") ) label.card-hint-feedback-label #{translate("log_hint_feedback_label")} a.card-hint-feedback-positive( - ng-click="feedbackSent = true;" + ng-click="trackLogHintsPositiveFeedback(entry.ruleId); feedbackSent = true;" href ) #{translate("answer_yes")} span  /  a.card-hint-feedback-negative( - ng-click="feedbackSent = true;" + ng-click="trackLogHintsNegativeFeedback(entry.ruleId); feedbackSent = true;" href ) #{translate("answer_no")} .card-hint-feedback(ng-show="feedbackSent") diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index b9b8d234dd..261730e1ba 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -15,6 +15,13 @@ define [ $scope.shouldShowLogs = false $scope.wikiEnabled = window.wikiEnabled; + # log hints tracking + trackLogHintsFeedback = (isPositive, hintId) -> + event_tracking.send 'log-hints', (if isPositive then 'feedback-positive' else 'feedback-negative'), hintId + + $scope.trackLogHintsPositiveFeedback = (hintId) -> trackLogHintsFeedback true, hintId + $scope.trackLogHintsNegativeFeedback = (hintId) -> trackLogHintsFeedback false, hintId + if ace.require("ace/lib/useragent").isMac $scope.modifierKey = "Cmd" else From d93c96d43c7470ea42dc882ef8e98b3a92b13dad Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Thu, 30 Jun 2016 11:30:43 +0100 Subject: [PATCH 09/20] Improve log hints ids. --- .../coffee/ide/human-readable-logs/HumanReadableLogs.coffee | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee b/services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee index 31fc11b6a3..747ca1ad08 100644 --- a/services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee +++ b/services/web/public/coffee/ide/human-readable-logs/HumanReadableLogs.coffee @@ -12,7 +12,8 @@ define [ ruleDetails = _getRule entry.message if (ruleDetails?) - entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/[^a-zA-Z0-9]/g, '_').toLowerCase() if ruleDetails.regexToMatch? + entry.ruleId = 'hint_' + ruleDetails.regexToMatch.toString().replace(/\s/g, '_').slice(1, -1) if ruleDetails.regexToMatch? + entry.humanReadableHint = ruleDetails.humanReadableHint if ruleDetails.humanReadableHint? entry.extraInfoURL = ruleDetails.extraInfoURL if ruleDetails.extraInfoURL? From a0fcc7e3ed7cdd0b21224eb1fccc5cbf0c64c70d Mon Sep 17 00:00:00 2001 From: James Allen Date: Thu, 30 Jun 2016 13:56:10 +0100 Subject: [PATCH 10/20] Skip null user objects when getting collaborators --- .../Features/Collaborators/CollaboratorsHandler.coffee | 9 +++++++-- .../Collaborators/CollaboratorsHandlerTests.coffee | 4 +++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee index 71737eecff..b8e0f3e606 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee @@ -30,12 +30,17 @@ module.exports = CollaboratorsHandler = getMembersWithPrivilegeLevels: (project_id, callback = (error, members) ->) -> CollaboratorsHandler.getMemberIdsWithPrivilegeLevels project_id, (error, members = []) -> return callback(error) if error? + result = [] async.mapLimit members, 3, (member, cb) -> UserGetter.getUser member.id, (error, user) -> return cb(error) if error? - return cb(null, { user: user, privilegeLevel: member.privilegeLevel }) - callback + if user? + result.push { user: user, privilegeLevel: member.privilegeLevel } + cb() + (error) -> + return callback(error) if error? + callback null, result getMemberIdPrivilegeLevel: (user_id, project_id, callback = (error, privilegeLevel) ->) -> # In future if the schema changes and getting all member ids is more expensive (multiple documents) diff --git a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee index 632b43e7f2..bb7e370044 100644 --- a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee +++ b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee @@ -77,17 +77,19 @@ describe "CollaboratorsHandler", -> { id: "read-only-ref-2", privilegeLevel: "readOnly" } { id: "read-write-ref-1", privilegeLevel: "readAndWrite" } { id: "read-write-ref-2", privilegeLevel: "readAndWrite" } + { id: "doesnt-exist", privilegeLevel: "readAndWrite" } ]) @UserGetter.getUser = sinon.stub() @UserGetter.getUser.withArgs("read-only-ref-1").yields(null, { _id: "read-only-ref-1" }) @UserGetter.getUser.withArgs("read-only-ref-2").yields(null, { _id: "read-only-ref-2" }) @UserGetter.getUser.withArgs("read-write-ref-1").yields(null, { _id: "read-write-ref-1" }) @UserGetter.getUser.withArgs("read-write-ref-2").yields(null, { _id: "read-write-ref-2" }) + @UserGetter.getUser.withArgs("doesnt-exist").yields(null, null) @CollaboratorHandler.getMembersWithPrivilegeLevels @project_id, @callback it "should return an array of members with their privilege levels", -> @callback - .calledWith(undefined, [ + .calledWith(null, [ { user: { _id: "read-only-ref-1" }, privilegeLevel: "readOnly" } { user: { _id: "read-only-ref-2" }, privilegeLevel: "readOnly" } { user: { _id: "read-write-ref-1" }, privilegeLevel: "readAndWrite" } From b76cc7e31462999f8c3071beb4136eb9fee7d7b2 Mon Sep 17 00:00:00 2001 From: James Allen Date: Thu, 30 Jun 2016 14:21:44 +0100 Subject: [PATCH 11/20] Remove a user from being a collaborator when their account is deleted --- .../Collaborators/CollaboratorsHandler.coffee | 11 +++++++++++ .../Features/Project/ProjectDeleter.coffee | 8 +++++--- .../CollaboratorsHandlerTests.coffee | 19 ++++++++++++++++--- .../coffee/Project/ProjectDeleterTests.coffee | 10 +++++++++- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee index b8e0f3e606..5f2580497d 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee @@ -87,6 +87,17 @@ module.exports = CollaboratorsHandler = logger.error err: err, "problem removing user from project collaberators" callback(err) + removeUserFromAllProjets: (user_id, callback = (error) ->) -> + CollaboratorsHandler.getProjectsUserIsCollaboratorOf user_id, { _id: 1 }, (error, readAndWriteProjects = [], readOnlyProjects = []) -> + return callback(error) if error? + allProjects = readAndWriteProjects.concat(readOnlyProjects) + jobs = [] + for project in allProjects + do (project) -> + jobs.push (cb) -> + CollaboratorsHandler.removeUserFromProject project._id, user_id, cb + async.series jobs, callback + addEmailToProject: (project_id, adding_user_id, unparsed_email, privilegeLevel, callback = (error, user) ->) -> emails = mimelib.parseAddresses(unparsed_email) email = emails[0]?.address?.toLowerCase() diff --git a/services/web/app/coffee/Features/Project/ProjectDeleter.coffee b/services/web/app/coffee/Features/Project/ProjectDeleter.coffee index 8ba8a65845..f398ea75b5 100644 --- a/services/web/app/coffee/Features/Project/ProjectDeleter.coffee +++ b/services/web/app/coffee/Features/Project/ProjectDeleter.coffee @@ -24,9 +24,11 @@ module.exports = ProjectDeleter = update = {deletedByExternalDataSource: false} Project.update conditions, update, {}, callback - deleteUsersProjects: (owner_id, callback)-> - logger.log owner_id:owner_id, "deleting users projects" - Project.remove owner_ref:owner_id, callback + deleteUsersProjects: (user_id, callback)-> + logger.log {user_id}, "deleting users projects" + Project.remove owner_ref:user_id, (error) -> + return callback(error) if error? + CollaboratorsHandler.removeUserFromAllProjets user_id, callback deleteProject: (project_id, callback = (error) ->) -> # archiveProject takes care of the clean-up diff --git a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee index bb7e370044..645c39076c 100644 --- a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee +++ b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee @@ -276,6 +276,19 @@ describe "CollaboratorsHandler", -> it "should not add any users to the proejct", -> @CollaboratorHandler.addUserIdToProject.called.should.equal false - - - + describe "removeUserFromAllProjets", -> + beforeEach (done) -> + @CollaboratorHandler.getProjectsUserIsCollaboratorOf = sinon.stub() + @CollaboratorHandler.getProjectsUserIsCollaboratorOf.withArgs(@user_id, { _id: 1 }).yields( + null, + [ { _id: "read-and-write-0" }, { _id: "read-and-write-1" } ], + [ { _id: "read-only-0" }, { _id: "read-only-1" } ] + ) + @CollaboratorHandler.removeUserFromProject = sinon.stub().yields() + @CollaboratorHandler.removeUserFromAllProjets @user_id, done + + it "should remove the user from each project", -> + for project_id in ["read-and-write-0", "read-and-write-1", "read-only-0", "read-only-1"] + @CollaboratorHandler.removeUserFromProject + .calledWith(project_id, @user_id) + .should.equal true \ No newline at end of file diff --git a/services/web/test/UnitTests/coffee/Project/ProjectDeleterTests.coffee b/services/web/test/UnitTests/coffee/Project/ProjectDeleterTests.coffee index 601f7867b0..6a99ed8150 100644 --- a/services/web/test/UnitTests/coffee/Project/ProjectDeleterTests.coffee +++ b/services/web/test/UnitTests/coffee/Project/ProjectDeleterTests.coffee @@ -27,13 +27,15 @@ describe 'ProjectDeleter', -> removeProjectFromAllTags: sinon.stub().callsArgWith(2) @ProjectGetter = getProject:sinon.stub() + @CollaboratorsHandler = + removeUserFromAllProjets: sinon.stub().yields() @deleter = SandboxedModule.require modulePath, requires: "../Editor/EditorController": @editorController '../../models/Project':{Project:@Project} '../DocumentUpdater/DocumentUpdaterHandler': @documentUpdaterHandler "../Tags/TagsHandler":@TagsHandler "../FileStore/FileStoreHandler": @FileStoreHandler = {} - "../Collaborators/CollaboratorsHandler": @CollaboratorsHandler = {} + "../Collaborators/CollaboratorsHandler": @CollaboratorsHandler "./ProjectGetter": @ProjectGetter 'logger-sharelatex': log:-> @@ -74,6 +76,12 @@ describe 'ProjectDeleter', -> @Project.remove.calledWith(owner_ref:user_id).should.equal true done() + it "should remove all the projects the user is a collaborator of", (done)-> + user_id = 1234 + @deleter.deleteUsersProjects user_id, => + @CollaboratorsHandler.removeUserFromAllProjets.calledWith(user_id).should.equal true + done() + describe "deleteProject", -> beforeEach (done) -> @project_id = "mock-project-id-123" From 882e28a8110509c1b6a70ac14ef5f1ed6bb5d42f Mon Sep 17 00:00:00 2001 From: James Allen Date: Thu, 30 Jun 2016 14:30:04 +0100 Subject: [PATCH 12/20] Don't choke on null projects --- .../Features/Collaborators/CollaboratorsHandler.coffee | 1 + .../coffee/Collaborators/CollaboratorsHandlerTests.coffee | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee index 5f2580497d..81557fea42 100644 --- a/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee +++ b/services/web/app/coffee/Features/Collaborators/CollaboratorsHandler.coffee @@ -95,6 +95,7 @@ module.exports = CollaboratorsHandler = for project in allProjects do (project) -> jobs.push (cb) -> + return cb() if !project? CollaboratorsHandler.removeUserFromProject project._id, user_id, cb async.series jobs, callback diff --git a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee index 645c39076c..37e39aaacb 100644 --- a/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee +++ b/services/web/test/UnitTests/coffee/Collaborators/CollaboratorsHandlerTests.coffee @@ -276,13 +276,13 @@ describe "CollaboratorsHandler", -> it "should not add any users to the proejct", -> @CollaboratorHandler.addUserIdToProject.called.should.equal false - describe "removeUserFromAllProjets", -> + describe "removeUserFromAllProjects", -> beforeEach (done) -> @CollaboratorHandler.getProjectsUserIsCollaboratorOf = sinon.stub() @CollaboratorHandler.getProjectsUserIsCollaboratorOf.withArgs(@user_id, { _id: 1 }).yields( null, - [ { _id: "read-and-write-0" }, { _id: "read-and-write-1" } ], - [ { _id: "read-only-0" }, { _id: "read-only-1" } ] + [ { _id: "read-and-write-0" }, { _id: "read-and-write-1" }, null ], + [ { _id: "read-only-0" }, { _id: "read-only-1" }, null ] ) @CollaboratorHandler.removeUserFromProject = sinon.stub().yields() @CollaboratorHandler.removeUserFromAllProjets @user_id, done From c04e00026ba4b87ffcff847a9aafb84f36c8f0ef Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 30 Jun 2016 09:43:09 +0100 Subject: [PATCH 13/20] remove scaffolding for per-user compiles so that it is always by default --- .../coffee/Features/Compile/CompileController.coffee | 12 ++++-------- .../coffee/Features/Compile/CompileManager.coffee | 2 +- services/web/config/settings.defaults.coffee | 4 ++++ .../coffee/ide/pdf/controllers/PdfController.coffee | 10 ---------- .../controllers/WordCountModalController.coffee | 6 +----- .../coffee/Compile/CompileControllerTests.coffee | 6 +----- .../coffee/Compile/CompileManagerTests.coffee | 2 +- 7 files changed, 12 insertions(+), 30 deletions(-) diff --git a/services/web/app/coffee/Features/Compile/CompileController.coffee b/services/web/app/coffee/Features/Compile/CompileController.coffee index 5f3edd4de5..a790948db5 100755 --- a/services/web/app/coffee/Features/Compile/CompileController.coffee +++ b/services/web/app/coffee/Features/Compile/CompileController.coffee @@ -29,8 +29,6 @@ module.exports = CompileController = options.compiler = req.body.compiler if req.body?.draft options.draft = req.body.draft - if req.query?.isolated is "true" - options.isolated = true logger.log {options:options, project_id:project_id, user_id:user_id}, "got compile request" CompileManager.compile project_id, user_id, options, (error, status, outputFiles, clsiServerId, limits, validationProblems) -> return next(error) if error? @@ -44,17 +42,15 @@ module.exports = CompileController = } _compileAsUser: (req, callback) -> - # callback with user_id if isolated flag is set on request, undefined otherwise - isolated = req.query?.isolated is "true" - if isolated + # callback with user_id if per-user, undefined otherwise + if not Settings.disablePerUserCompiles AuthenticationController.getLoggedInUserId req, callback # -> (error, user_id) else callback() # do a per-project compile, not per-user _downloadAsUser: (req, callback) -> - # callback with user_id if isolated flag or user_id param is set on request, undefined otherwise - isolated = req.query?.isolated is "true" or req.params.user_id? - if isolated + # callback with user_id if per-user, undefined otherwise + if not Settings.disablePerUserCompiles AuthenticationController.getLoggedInUserId req, callback # -> (error, user_id) else callback() # do a per-project compile, not per-user diff --git a/services/web/app/coffee/Features/Compile/CompileManager.coffee b/services/web/app/coffee/Features/Compile/CompileManager.coffee index 8350ca1196..c561576525 100755 --- a/services/web/app/coffee/Features/Compile/CompileManager.coffee +++ b/services/web/app/coffee/Features/Compile/CompileManager.coffee @@ -38,7 +38,7 @@ module.exports = CompileManager = for key, value of limits options[key] = value # only pass user_id down to clsi if this is a per-user compile - compileAsUser = if options.isolated then user_id else undefined + compileAsUser = if Settings.disablePerUserCompiles then undefined else user_id ClsiManager.sendRequest project_id, compileAsUser, options, (error, status, outputFiles, clsiServerId, validationProblems) -> return callback(error) if error? logger.log files: outputFiles, "output files" diff --git a/services/web/config/settings.defaults.coffee b/services/web/config/settings.defaults.coffee index 25b240c08d..e6fb6a505d 100644 --- a/services/web/config/settings.defaults.coffee +++ b/services/web/config/settings.defaults.coffee @@ -262,6 +262,10 @@ module.exports = settings = # Should we allow access to any page without logging in? This includes # public projects, /learn, /templates, about pages, etc. allowPublicAccess: if process.env["SHARELATEX_ALLOW_PUBLIC_ACCESS"] == 'true' then true else false + + # Use a single compile directory for all users in a project + # (otherwise each user has their own directory) + disablePerUserCompiles: true # Maximum size of text documents in the real-time editing system. max_doc_length: 2 * 1024 * 1024 # 2mb diff --git a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee index b9b8d234dd..e095df5695 100644 --- a/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee +++ b/services/web/public/coffee/ide/pdf/controllers/PdfController.coffee @@ -50,8 +50,6 @@ define [ params = {} if options.isAutoCompile params["auto_compile"]=true - if perUserCompile # send ?isolated=true for per-user compiles - params["isolated"] = true return $http.post url, { rootDoc_id: options.rootDocOverride_id or null draft: $scope.draft @@ -125,9 +123,6 @@ define [ # convert the qs hash into a query string and append it $scope.pdf.qs = createQueryString qs $scope.pdf.url += $scope.pdf.qs - # special case for the download url - if perUserCompile - qs.isolated = true # Save all downloads as files qs.popupDownload = true $scope.pdf.downloadUrl = "/project/#{$scope.project_id}/output/output.pdf" + createQueryString(qs) @@ -147,8 +142,6 @@ define [ else file.name = file.path qs = {} - if perUserCompile - qs.isolated = true if response.clsiServerId? qs.clsiserverid = response.clsiServerId file.url = "/project/#{project_id}/output/#{file.path}" + createQueryString qs @@ -274,7 +267,6 @@ define [ method: "DELETE" params: clsiserverid:ide.clsiServerId - isolated: perUserCompile headers: "X-Csrf-Token": window.csrfToken } @@ -361,7 +353,6 @@ define [ line: row + 1 column: column clsiserverid:ide.clsiServerId - isolated: perUserCompile } }) .success (data) -> @@ -407,7 +398,6 @@ define [ h: h.toFixed(2) v: v.toFixed(2) clsiserverid:ide.clsiServerId - isolated: perUserCompile } }) .success (data) -> diff --git a/services/web/public/coffee/ide/wordcount/controllers/WordCountModalController.coffee b/services/web/public/coffee/ide/wordcount/controllers/WordCountModalController.coffee index 5166a32ae1..2aa4efb505 100644 --- a/services/web/public/coffee/ide/wordcount/controllers/WordCountModalController.coffee +++ b/services/web/public/coffee/ide/wordcount/controllers/WordCountModalController.coffee @@ -5,15 +5,11 @@ define [ $scope.status = loading:true - # enable per-user containers by default - perUserCompile = true - opts = url:"/project/#{ide.project_id}/wordcount" method:"GET" params: clsiserverid:ide.clsiServerId - isolated: perUserCompile $http opts .success (data) -> $scope.status.loading = false @@ -22,4 +18,4 @@ define [ $scope.status.error = true $scope.cancel = () -> - $modalInstance.dismiss('cancel') \ No newline at end of file + $modalInstance.dismiss('cancel') diff --git a/services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee b/services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee index 97b41fb33b..d7a13578e2 100644 --- a/services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee +++ b/services/web/test/UnitTests/coffee/Compile/CompileControllerTests.coffee @@ -139,7 +139,7 @@ describe "CompileController", -> .should.equal true it "should proxy the PDF from the CLSI", -> - @CompileController.proxyToClsi.calledWith(@project_id, "/project/#{@project_id}/output/output.pdf", @req, @res, @next).should.equal true + @CompileController.proxyToClsi.calledWith(@project_id, "/project/#{@project_id}/user/#{@user_id}/output/output.pdf", @req, @res, @next).should.equal true describe "when the pdf is not going to be used in pdfjs viewer", -> @@ -338,8 +338,6 @@ describe "CompileController", -> @req = params: project_id:@project_id - query: - isolated: "true" @CompileManager.compile.callsArgWith(3) @CompileController.proxyToClsi = sinon.stub() @res = @@ -362,8 +360,6 @@ describe "CompileController", -> @CompileManager.wordCount = sinon.stub().callsArgWith(3, null, {content:"body"}) @req.params = Project_id: @project_id - @req.query = - isolated: "true" @res.send = sinon.stub() @res.contentType = sinon.stub() @CompileController.wordCount @req, @res, @next diff --git a/services/web/test/UnitTests/coffee/Compile/CompileManagerTests.coffee b/services/web/test/UnitTests/coffee/Compile/CompileManagerTests.coffee index 82a4ab734b..849e9e8ccc 100644 --- a/services/web/test/UnitTests/coffee/Compile/CompileManagerTests.coffee +++ b/services/web/test/UnitTests/coffee/Compile/CompileManagerTests.coffee @@ -71,7 +71,7 @@ describe "CompileManager", -> it "should run the compile with the compile limits", -> @ClsiManager.sendRequest - .calledWith(@project_id, undefined, { + .calledWith(@project_id, @user_id, { timeout: @limits.timeout }) .should.equal true From 7cb266d904f29270e539ccc4875aed495def1539 Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Thu, 30 Jun 2016 14:58:54 +0100 Subject: [PATCH 14/20] removed imagemin --- services/web/Gruntfile.coffee | 25 +++++++++++++------------ services/web/package.json | 1 - 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index 1fae80dd90..a52c1b8a55 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -17,7 +17,7 @@ module.exports = (grunt) -> grunt.loadNpmTasks 'grunt-contrib-watch' grunt.loadNpmTasks 'grunt-parallel' grunt.loadNpmTasks 'grunt-exec' - grunt.loadNpmTasks 'grunt-contrib-imagemin' + # grunt.loadNpmTasks 'grunt-contrib-imagemin' grunt.loadNpmTasks 'grunt-contrib-cssmin' config = @@ -47,17 +47,17 @@ module.exports = (grunt) -> stream:true - imagemin: - dynamic: - files: [{ - expand: true - cwd: 'public/img/' - src: ['**/*.{png,jpg,gif}'] - dest: 'public/img/' - }] - options: - interlaced:false - optimizationLevel: 7 + # imagemin: + # dynamic: + # files: [{ + # expand: true + # cwd: 'public/img/' + # src: ['**/*.{png,jpg,gif}'] + # dest: 'public/img/' + # }] + # options: + # interlaced:false + # optimizationLevel: 7 @@ -218,6 +218,7 @@ module.exports = (grunt) -> pattern: "@@RELEASE@@" replacement: process.env.BUILD_NUMBER || "(unknown build)" + availabletasks: diff --git a/services/web/package.json b/services/web/package.json index 8d14a350dc..86c7dee403 100644 --- a/services/web/package.json +++ b/services/web/package.json @@ -70,7 +70,6 @@ "grunt-contrib-clean": "0.5.0", "grunt-contrib-coffee": "0.10.0", "grunt-contrib-cssmin": "^1.0.1", - "grunt-contrib-imagemin": "^1.0.1", "grunt-contrib-less": "0.9.0", "grunt-contrib-requirejs": "0.4.1", "grunt-contrib-watch": "^1.0.0", From 73ad1fde5ca0e2f362c9b9d70ea4527c28201ec7 Mon Sep 17 00:00:00 2001 From: Brian Gough Date: Thu, 30 Jun 2016 15:15:37 +0100 Subject: [PATCH 15/20] comment out disabling of per user compiles --- services/web/config/settings.defaults.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/web/config/settings.defaults.coffee b/services/web/config/settings.defaults.coffee index e6fb6a505d..47902d5826 100644 --- a/services/web/config/settings.defaults.coffee +++ b/services/web/config/settings.defaults.coffee @@ -265,7 +265,7 @@ module.exports = settings = # Use a single compile directory for all users in a project # (otherwise each user has their own directory) - disablePerUserCompiles: true + # disablePerUserCompiles: true # Maximum size of text documents in the real-time editing system. max_doc_length: 2 * 1024 * 1024 # 2mb From 6f4a7f4779a22e1668737a21f39afe19c956a8aa Mon Sep 17 00:00:00 2001 From: Henry Oswald Date: Fri, 1 Jul 2016 15:04:39 +0100 Subject: [PATCH 16/20] mvp for using sprites for flags, needs border removing --- services/web/Gruntfile.coffee | 11 +- services/web/app/views/layout/footer.jade | 6 +- services/web/public/img/sprite.png | Bin 0 -> 14176 bytes .../web/public/stylesheets/app/sprites.less | 105 ++++++++++++++++++ services/web/public/stylesheets/style.less | 1 + 5 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 services/web/public/img/sprite.png create mode 100644 services/web/public/stylesheets/app/sprites.less diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index a52c1b8a55..99f29ed2a6 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -17,8 +17,9 @@ module.exports = (grunt) -> grunt.loadNpmTasks 'grunt-contrib-watch' grunt.loadNpmTasks 'grunt-parallel' grunt.loadNpmTasks 'grunt-exec' - # grunt.loadNpmTasks 'grunt-contrib-imagemin' grunt.loadNpmTasks 'grunt-contrib-cssmin' + # grunt.loadNpmTasks 'grunt-contrib-imagemin' + grunt.loadNpmTasks 'grunt-sprity' config = @@ -59,6 +60,14 @@ module.exports = (grunt) -> # interlaced:false # optimizationLevel: 7 + sprity: + + sprite: + options: + cssPath:"/img/" + 'style': '../../public/stylesheets/app/sprites.less' + src: ['./public/img/flags/24/*.png'] + dest: './public/img/sprite', coffee: diff --git a/services/web/app/views/layout/footer.jade b/services/web/app/views/layout/footer.jade index 7ef26b3493..bc57352086 100644 --- a/services/web/app/views/layout/footer.jade +++ b/services/web/app/views/layout/footer.jade @@ -15,7 +15,7 @@ footer.site-footer aria-expanded="false", tooltip="#{translate('language')}" ) - img(src="/img/flags/24/#{currentLngCode}.png") + img(class="icon icon-#{currentLngCode}") ul.dropdown-menu(role="menu") li.dropdown-header #{translate("language")} @@ -23,9 +23,9 @@ footer.site-footer if !subdomainDetails.hide li.lngOption a.menu-indent(href=subdomainDetails.url+currentUrl) - img(src="/img/flags/24/#{subdomainDetails.lngCode}.png") + img(class="icon icon-#{subdomainDetails.lngCode}") | #{translate(subdomainDetails.lngCode)} - + //- img(src="/img/flags/24/.png") each item in nav.left_footer li if item.url diff --git a/services/web/public/img/sprite.png b/services/web/public/img/sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..4de03050d5b139f21a4b86cfe5763fb74c8f266e GIT binary patch literal 14176 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
  • 7G+Z@k{rk6)92`buTB}s&hrX%FYDmH^`y6>mvM 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 Date: Fri, 1 Jul 2016 16:02:01 +0100 Subject: [PATCH 17/20] Use a figure element instead of an img, as there is no src attribute. --- services/web/app/views/layout/footer.jade | 4 ++-- services/web/public/stylesheets/components/footer.less | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/services/web/app/views/layout/footer.jade b/services/web/app/views/layout/footer.jade index bc57352086..ea7a36e2ae 100644 --- a/services/web/app/views/layout/footer.jade +++ b/services/web/app/views/layout/footer.jade @@ -15,7 +15,7 @@ footer.site-footer aria-expanded="false", tooltip="#{translate('language')}" ) - img(class="icon icon-#{currentLngCode}") + figure(class="icon icon-lang icon-#{currentLngCode}") ul.dropdown-menu(role="menu") li.dropdown-header #{translate("language")} @@ -23,7 +23,7 @@ footer.site-footer if !subdomainDetails.hide li.lngOption a.menu-indent(href=subdomainDetails.url+currentUrl) - img(class="icon icon-#{subdomainDetails.lngCode}") + figure(class="icon icon-lang icon-#{subdomainDetails.lngCode}") | #{translate(subdomainDetails.lngCode)} //- img(src="/img/flags/24/.png") each item in nav.left_footer diff --git a/services/web/public/stylesheets/components/footer.less b/services/web/public/stylesheets/components/footer.less index 7a3bc66723..32adc1ee90 100644 --- a/services/web/public/stylesheets/components/footer.less +++ b/services/web/public/stylesheets/components/footer.less @@ -23,3 +23,8 @@ footer.site-footer { } } } + +.icon-lang { + display: inline-block; + vertical-align: middle; +} \ No newline at end of file From 64a73b0356ff85a40407a40399cd66f1b78ef8d1 Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Fri, 1 Jul 2016 16:02:40 +0100 Subject: [PATCH 18/20] Disable default 4px margin on grunt-sprity, also add the built files. --- services/web/Gruntfile.coffee | 1 + services/web/public/img/sprite.png | Bin 14176 -> 12032 bytes .../web/public/stylesheets/app/sprites.less | 118 +++++++++--------- 3 files changed, 60 insertions(+), 59 deletions(-) diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index 99f29ed2a6..988172e257 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -66,6 +66,7 @@ module.exports = (grunt) -> options: cssPath:"/img/" 'style': '../../public/stylesheets/app/sprites.less' + margin: 0 src: ['./public/img/flags/24/*.png'] dest: './public/img/sprite', diff --git a/services/web/public/img/sprite.png b/services/web/public/img/sprite.png index 4de03050d5b139f21a4b86cfe5763fb74c8f266e..366d994ce8428da6c637f81a2cfa683705745ed1 100644 GIT binary patch literal 12032 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
  • 7G+Z@k{rk6)92`buTB}s&hrX%FYDmH^`y6>mvM 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 Date: Mon, 4 Jul 2016 16:03:29 +0100 Subject: [PATCH 19/20] Comment out sprity and leave a not in README.md. --- services/web/Gruntfile.coffee | 19 +++++++++---------- services/web/README.md | 8 ++++++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/services/web/Gruntfile.coffee b/services/web/Gruntfile.coffee index 988172e257..78ce4190d0 100644 --- a/services/web/Gruntfile.coffee +++ b/services/web/Gruntfile.coffee @@ -19,7 +19,7 @@ module.exports = (grunt) -> grunt.loadNpmTasks 'grunt-exec' grunt.loadNpmTasks 'grunt-contrib-cssmin' # grunt.loadNpmTasks 'grunt-contrib-imagemin' - grunt.loadNpmTasks 'grunt-sprity' + # grunt.loadNpmTasks 'grunt-sprity' config = @@ -60,15 +60,14 @@ module.exports = (grunt) -> # interlaced:false # optimizationLevel: 7 - sprity: - - sprite: - options: - cssPath:"/img/" - 'style': '../../public/stylesheets/app/sprites.less' - margin: 0 - src: ['./public/img/flags/24/*.png'] - dest: './public/img/sprite', + # sprity: + # sprite: + # options: + # cssPath:"/img/" + # 'style': '../../public/stylesheets/app/sprites.less' + # margin: 0 + # src: ['./public/img/flags/24/*.png'] + # dest: './public/img/sprite' coffee: diff --git a/services/web/README.md b/services/web/README.md index 00d94343ab..323b43f028 100644 --- a/services/web/README.md +++ b/services/web/README.md @@ -6,9 +6,17 @@ web-sharelatex is the front-end web service of the open-source web-based collabo It serves all the HTML pages, CSS and javascript to the client. web-sharelatex also contains a lot of logic around creating and editing projects, and account management. + The rest of the ShareLaTeX stack, along with information about contributing can be found in the [sharelatex/sharelatex](https://github.com/sharelatex/sharelatex) repository. +Build process +---------------- + +web-sharelatex uses [Grunt](http://gruntjs.com/) to build its front-end related assets. + +Image processing tasks are commented out in the gruntfile and the needed packages aren't presently in the project's `package.json`. If the images need to be processed again (minified and sprited), start by fetching the packages (`npm install grunt-contrib-imagemin grunt-sprity`), then *decomment* the tasks in `Gruntfile.coffee`. After this, the tasks can be called (explicitly, via `grunt imagemin` and `grunt sprity`). + Unit test status ---------------- From fac3698c40a2590e879c400901a3d6332960b86b Mon Sep 17 00:00:00 2001 From: Paulo Reis Date: Tue, 5 Jul 2016 11:08:58 +0100 Subject: [PATCH 20/20] Better namespacing of sprite CSS classes. --- services/web/app/views/layout/footer.jade | 4 +- .../web/public/stylesheets/app/sprites.less | 42 +++++++++---------- .../public/stylesheets/components/footer.less | 2 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/services/web/app/views/layout/footer.jade b/services/web/app/views/layout/footer.jade index ea7a36e2ae..efd64b6f6e 100644 --- a/services/web/app/views/layout/footer.jade +++ b/services/web/app/views/layout/footer.jade @@ -15,7 +15,7 @@ footer.site-footer aria-expanded="false", tooltip="#{translate('language')}" ) - figure(class="icon icon-lang icon-#{currentLngCode}") + figure(class="sprite-icon sprite-icon-lang sprite-icon-#{currentLngCode}") ul.dropdown-menu(role="menu") li.dropdown-header #{translate("language")} @@ -23,7 +23,7 @@ footer.site-footer if !subdomainDetails.hide li.lngOption a.menu-indent(href=subdomainDetails.url+currentUrl) - figure(class="icon icon-lang icon-#{subdomainDetails.lngCode}") + figure(class="sprite-icon sprite-icon-lang sprite-icon-#{subdomainDetails.lngCode}") | #{translate(subdomainDetails.lngCode)} //- img(src="/img/flags/24/.png") each item in nav.left_footer diff --git a/services/web/public/stylesheets/app/sprites.less b/services/web/public/stylesheets/app/sprites.less index 8b658648f0..b64e84ad68 100644 --- a/services/web/public/stylesheets/app/sprites.less +++ b/services/web/public/stylesheets/app/sprites.less @@ -1,104 +1,104 @@ -.icon { +.sprite-icon { background-image: url('/img/sprite.png'); } -.icon-ko { +.sprite-icon-ko { background-position: -0px -0px; width: 24px; height: 24px; } -.icon-cn { +.sprite-icon-cn { background-position: -0px -24px; width: 24px; height: 24px; } -.icon-da { +.sprite-icon-da { background-position: -0px -48px; width: 24px; height: 24px; } -.icon-de { +.sprite-icon-de { background-position: -0px -72px; width: 24px; height: 24px; } -.icon-en { +.sprite-icon-en { background-position: -0px -96px; width: 24px; height: 24px; } -.icon-es { +.sprite-icon-es { background-position: -0px -120px; width: 24px; height: 24px; } -.icon-fi { +.sprite-icon-fi { background-position: -0px -144px; width: 24px; height: 24px; } -.icon-fr { +.sprite-icon-fr { background-position: -0px -168px; width: 24px; height: 24px; } -.icon-it { +.sprite-icon-it { background-position: -0px -192px; width: 24px; height: 24px; } -.icon-ja { +.sprite-icon-ja { background-position: -0px -216px; width: 24px; height: 24px; } -.icon-cs { +.sprite-icon-cs { background-position: -0px -240px; width: 24px; height: 24px; } -.icon-nl { +.sprite-icon-nl { background-position: -0px -264px; width: 24px; height: 24px; } -.icon-no { +.sprite-icon-no { background-position: -0px -288px; width: 24px; height: 24px; } -.icon-pl { +.sprite-icon-pl { background-position: -0px -312px; width: 24px; height: 24px; } -.icon-pt { +.sprite-icon-pt { background-position: -0px -336px; width: 24px; height: 24px; } -.icon-ru { +.sprite-icon-ru { background-position: -0px -360px; width: 24px; height: 24px; } -.icon-sv { +.sprite-icon-sv { background-position: -0px -384px; width: 24px; height: 24px; } -.icon-tr { +.sprite-icon-tr { background-position: -0px -408px; width: 24px; height: 24px; } -.icon-uk { +.sprite-icon-uk { background-position: -0px -432px; width: 24px; height: 24px; } -.icon-zh-CN { +.sprite-icon-zh-CN { background-position: -0px -456px; width: 24px; height: 24px; diff --git a/services/web/public/stylesheets/components/footer.less b/services/web/public/stylesheets/components/footer.less index 32adc1ee90..e4e4f82da1 100644 --- a/services/web/public/stylesheets/components/footer.less +++ b/services/web/public/stylesheets/components/footer.less @@ -24,7 +24,7 @@ footer.site-footer { } } -.icon-lang { +.sprite-icon-lang { display: inline-block; vertical-align: middle; } \ No newline at end of file