diff --git a/services/web/app/coffee/Features/User/UserCreator.coffee b/services/web/app/coffee/Features/User/UserCreator.coffee index ee5a426e78..9218a48555 100644 --- a/services/web/app/coffee/Features/User/UserCreator.coffee +++ b/services/web/app/coffee/Features/User/UserCreator.coffee @@ -17,6 +17,7 @@ module.exports = user = new User() user.email = opts.email user.holdingAccount = opts.holdingAccount + user.ace.syntaxValidation = true username = opts.email.match(/^[^@]*/) if opts.first_name? and opts.first_name.length != 0 diff --git a/services/web/app/coffee/models/User.coffee b/services/web/app/coffee/models/User.coffee index 3b29936ab2..f120422128 100644 --- a/services/web/app/coffee/models/User.coffee +++ b/services/web/app/coffee/models/User.coffee @@ -26,7 +26,7 @@ UserSchema = new Schema autoComplete: {type : Boolean, default: true} spellCheckLanguage : {type : String, default: "en"} pdfViewer : {type : String, default: "pdfjs"} - syntaxValidation : {type : Boolean, default: true} + syntaxValidation : {type : Boolean} } features : { collaborators: { type:Number, default: Settings.defaultFeatures.collaborators } diff --git a/services/web/app/views/project/editor.jade b/services/web/app/views/project/editor.jade index 919e5ccd4e..82ebdcc72a 100644 --- a/services/web/app/views/project/editor.jade +++ b/services/web/app/views/project/editor.jade @@ -15,7 +15,8 @@ block content p.text-center.text-danger(ng-if="state.error").ng-cloak span(ng-bind-html="state.error") - + include ./editor/feature-onboarding + .global-alerts(ng-cloak) .alert.alert-danger.small(ng-if="connection.forced_disconnect") strong #{translate("disconnected")} @@ -88,7 +89,8 @@ block content block requirejs script(type="text/javascript" src='/socket.io/socket.io.js') - //- don't use cdn for worker + //- don't use cdn for workers + - var aceWorkerPath = buildJsPath(lib('ace'), {cdn:false,fingerprint:false}) - var pdfWorkerPath = buildJsPath('/libs/' + lib('pdfjs') + '/pdf.worker', {cdn:false,fingerprint:false}) //- We need to do .replace(/\//g, '\\/') do that '' -> '<\/script>' @@ -132,10 +134,6 @@ block requirejs } }; window.aceFingerprint = "#{fingerprint(jsPath + lib('ace') + '/ace.js')}" - - - var aceWorkerPath = user.betaProgram ? buildJsPath(lib('ace'), {cdn:false,fingerprint:false}) : "" // don't use cdn for worker - - script(type='text/javascript'). window.aceWorkerPath = "#{aceWorkerPath}"; script( diff --git a/services/web/app/views/project/editor/feature-onboarding.jade b/services/web/app/views/project/editor/feature-onboarding.jade new file mode 100644 index 0000000000..1a8d769088 --- /dev/null +++ b/services/web/app/views/project/editor/feature-onboarding.jade @@ -0,0 +1,54 @@ +.feat-onboard( + ng-controller="FeatureOnboardingController" + ng-class="('feat-onboard-step' + innerStep)" + ng-if="!state.loading && ui.showCodeCheckerOnboarding" + ng-cloak +) + .feat-onboard-wrapper + h1.feat-onboard-title + | Introducing  + span.feat-onboard-title-name Code check + div(ng-if="innerStep === 1;") + p.feat-onboard-description + span.feat-onboard-description-name Code check  + | will highlight potential problems in your LaTeX code, allowing you to handle errors earlier and become more productive. + .row + video.feat-onboard-video(autoplay, loop) + source(src="/img/teasers/code-checker/code-checker.mp4", type="video/mp4") + img(src="/img/teasers/code-checker/code-checker.gif") + .row.feat-onboard-adv-wrapper + .col-xs-4 + h2.feat-onboard-adv-title + | Missing  + span.feat-onboard-adv-title-highlight brackets + p Forgot to place a closing bracket? We'll warn you. + .col-xs-4 + h2.feat-onboard-adv-title + | Unclosed  + span.feat-onboard-adv-title-highlight environments + p + | Know when you are missing an  + code \end{...} + |  command. + .col-xs-4 + h2.feat-onboard-adv-title + | Incorrect  + span.feat-onboard-adv-title-highlight nesting + p + | Order matters. Get notified when you use an  + code \end{...} + |   too soon. + .feat-onboard-btn-wrapper + button.btn.btn-primary(ng-click="turnCodeCheckOn();") Yes, turn Code check on + .feat-onboard-btn-wrapper + button.btn.btn-default(ng-click="turnCodeCheckOff();") No, disable it for now + div(ng-if="innerStep === 2;") + p.feat-onboard-description + | Remember: you can always turn  + span.feat-onboard-description-name Code check  + em on  + | or  + em off  + |, in the settings menu. + .feat-onboard-btn-wrapper + button.btn.btn-primary(ng-click="dismiss();") OK, got it \ No newline at end of file diff --git a/services/web/app/views/project/editor/left-menu.jade b/services/web/app/views/project/editor/left-menu.jade index 20b0905abf..80d5c606ab 100644 --- a/services/web/app/views/project/editor/left-menu.jade +++ b/services/web/app/views/project/editor/left-menu.jade @@ -105,14 +105,13 @@ aside#left-menu.full-size( ng-options="o.v as o.n for o in [{ n: 'On', v: true }, { n: 'Off', v: false }]" ) - if (user.betaProgram) - .form-controls - label(for="syntaxValidation") #{translate("syntax_validation")} - select( - name="syntaxValidation" - ng-model="settings.syntaxValidation" - ng-options="o.v as o.n for o in [{ n: 'On', v: true }, { n: 'Off', v: false }]" - ) + .form-controls.code-check-setting + label(for="syntaxValidation") #{translate("syntax_validation")} + select( + name="syntaxValidation" + ng-model="settings.syntaxValidation" + ng-options="o.v as o.n for o in [{ n: 'On', v: true }, { n: 'Off', v: false }]" + ) .form-controls label(for="theme") #{translate("theme")} diff --git a/services/web/public/coffee/ide.coffee b/services/web/public/coffee/ide.coffee index fd6c1440ce..a7aa9add0b 100644 --- a/services/web/public/coffee/ide.coffee +++ b/services/web/public/coffee/ide.coffee @@ -10,6 +10,7 @@ define [ "ide/binary-files/BinaryFilesManager" "ide/references/ReferencesManager" "ide/SafariScrollPatcher" + "ide/FeatureOnboardingController" "ide/settings/index" "ide/share/index" "ide/chat/index" @@ -64,6 +65,7 @@ define [ view: "editor" chatOpen: false pdfLayout: 'sideBySide' + showCodeCheckerOnboarding: !window.userSettings.syntaxValidation? } $scope.user = window.user diff --git a/services/web/public/coffee/ide/FeatureOnboardingController.coffee b/services/web/public/coffee/ide/FeatureOnboardingController.coffee new file mode 100644 index 0000000000..a5687cb42f --- /dev/null +++ b/services/web/public/coffee/ide/FeatureOnboardingController.coffee @@ -0,0 +1,35 @@ +define [ + "base" +], (App) -> + App.controller "FeatureOnboardingController", ($scope, settings) -> + $scope.innerStep = 1 + + $scope.turnCodeCheckOn = () -> + settings.saveSettings({ syntaxValidation: true }) + $scope.settings.syntaxValidation = true + navToInnerStep2() + + $scope.turnCodeCheckOff = () -> + settings.saveSettings({ syntaxValidation: false }) + $scope.settings.syntaxValidation = false + navToInnerStep2() + + $scope.dismiss = () -> + $scope.ui.leftMenuShown = false + $scope.ui.showCodeCheckerOnboarding = false + + navToInnerStep2 = () -> + $scope.innerStep = 2 + $scope.ui.leftMenuShown = true + + handleKeypress = (e) -> + if e.keyCode == 13 + if $scope.innerStep == 1 + $scope.turnCodeCheckOn() + else + $scope.dismiss() + + $(document).on "keypress", handleKeypress + + $scope.$on "$destroy", () -> + $(document).off "keypress", handleKeypress \ No newline at end of file diff --git a/services/web/public/img/teasers/code-checker/code-checker.gif b/services/web/public/img/teasers/code-checker/code-checker.gif new file mode 100644 index 0000000000..9da06779ba Binary files /dev/null and b/services/web/public/img/teasers/code-checker/code-checker.gif differ diff --git a/services/web/public/img/teasers/code-checker/code-checker.mp4 b/services/web/public/img/teasers/code-checker/code-checker.mp4 new file mode 100644 index 0000000000..116274175f Binary files /dev/null and b/services/web/public/img/teasers/code-checker/code-checker.mp4 differ diff --git a/services/web/public/stylesheets/app/editor.less b/services/web/public/stylesheets/app/editor.less index f4abac0009..905cf269c5 100644 --- a/services/web/public/stylesheets/app/editor.less +++ b/services/web/public/stylesheets/app/editor.less @@ -11,6 +11,7 @@ @import "./editor/publish-template.less"; @import "./editor/online-users.less"; @import "./editor/hotkeys.less"; +@import "./editor/feature-onboarding.less"; .full-size { position: absolute; diff --git a/services/web/public/stylesheets/app/editor/feature-onboarding.less b/services/web/public/stylesheets/app/editor/feature-onboarding.less new file mode 100644 index 0000000000..4a123a35f3 --- /dev/null +++ b/services/web/public/stylesheets/app/editor/feature-onboarding.less @@ -0,0 +1,79 @@ +@feat-onboard-wrapper-width: 820px; +@feat-onboard-max-text-width: 750px; + +.feat-onboard { + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + display: flex; + justify-content: center; + align-items: center; + background-image: linear-gradient(rgba(0, 0, 0, .85), rgba(0, 0, 0, .85)); + background-repeat: no-repeat; + background-position-x: 0; + color: #FFF; + text-align: center; + z-index: 102; + transition: background-position ease-in-out @left-menu-animation-duration; + overflow: auto; +} + +.feat-onboard-step2 { + background-position-x: @left-menu-width; + + ~ #left-menu { + pointer-events: none; + + .code-check-setting { + box-shadow: 0 0 300px #000; + } + } +} + .feat-onboard-wrapper { + width: @feat-onboard-wrapper-width; + text-shadow: 0 0 70px rgba(255, 255, 255, 0.5); + } + .feat-onboard-title { + color: @brand-primary; + margin-bottom: 40px; + + } + .feat-onboard-title-name { + color: #FFF; + font-weight: bold; + } + + .feat-onboard-description { + max-width: @feat-onboard-max-text-width; + margin: 0 auto 30px; + padding: 0 80px; + } + .feat-onboard-description-name { + font-weight: bold; + } + + .feat-onboard-video { + box-shadow: 0 0 70px rgba(255, 255, 255, 0.3); + } + + .feat-onboard-adv-wrapper { + text-align: left; + margin-bottom: 30px; + } + .feat-onboard-adv-title { + color: #FFF; + font-size: 23px; + } + .feat-onboard-adv-title-highlight { + font-weight: bold; + } + + .feat-onboard-btn-wrapper { + margin-bottom: 10px; + + > .btn { + box-shadow: 0 0 70px rgba(255, 255, 255, 0.3); + } + } \ No newline at end of file diff --git a/services/web/public/stylesheets/app/editor/left-menu.less b/services/web/public/stylesheets/app/editor/left-menu.less index a44b7289ac..8172c44b90 100644 --- a/services/web/public/stylesheets/app/editor/left-menu.less +++ b/services/web/public/stylesheets/app/editor/left-menu.less @@ -1,6 +1,6 @@ #left-menu { position: absolute; - width: 260px; + width: @left-menu-width; padding: (@line-height-computed / 2); top: 0; bottom: 0; @@ -8,8 +8,8 @@ z-index: 100; overflow-y: auto; overflow-x: hidden; - -webkit-transition: left ease-in-out 0.35s; - transition: left ease-in-out 0.35s; + -webkit-transition: left ease-in-out @left-menu-animation-duration; + transition: left ease-in-out @left-menu-animation-duration; font-size: 14px; left: -280px; diff --git a/services/web/public/stylesheets/core/variables.less b/services/web/public/stylesheets/core/variables.less index c9a3fcda62..a642ab97bc 100755 --- a/services/web/public/stylesheets/core/variables.less +++ b/services/web/public/stylesheets/core/variables.less @@ -820,6 +820,9 @@ // Custom +@left-menu-width: 260px; +@left-menu-animation-duration: 0.35s; + @toolbar-border-color: @gray-lighter; @file-tree-droppable-background-color: rgb(252, 231, 199); diff --git a/services/web/test/UnitTests/coffee/User/UserCreatorTests.coffee b/services/web/test/UnitTests/coffee/User/UserCreatorTests.coffee index c2f4ea292f..1f04d2ef3c 100644 --- a/services/web/test/UnitTests/coffee/User/UserCreatorTests.coffee +++ b/services/web/test/UnitTests/coffee/User/UserCreatorTests.coffee @@ -9,7 +9,7 @@ describe "UserCreator", -> beforeEach -> self = @ - @user = {_id:"12390i"} + @user = {_id:"12390i", ace: {}} @user.save = sinon.stub().callsArgWith(0) @UserModel = class Project constructor: ->