NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name DuoWriter — translate into your target language on Duolingo // @description Helps you practice writing and thinking in your target language // @match *://www.duolingo.com/* // @author dogewithflowers // @icon https://res.cloudinary.com/dn6n8yqqh/image/upload/c_scale,h_214/v1555635245/Icon_qqbnzf.png // @namespace duo-sntnce-trainer // @version 1.1 // @copyright 2019, vplameniraket (https://openuserjs.org/users/vplameniraket) // @license MIT // @grant GM_addStyle // @run-at document-end // ==/UserScript== if (/\.com\/global\-practice$/g.test(window.location.href)) addTemporaryStyle('', 'body > *:not(#translationExercise):not(#table-wrap) { opacity: 0; }'); // CSS + HTML GM_addStyle('.sentences-table{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;color:#222;background-color:#fdfdfd;border-left:2px solid #e5e5e5;-ms-flex-line-pack:start;align-content:flex-start}.sentences-table.requested{max-height:384px;min-height:300px;overflow-y:scroll;border:2px solid #e5e5e5;border-radius:10px}.sentences-table:not(.requested){position:fixed;z-index:99999999;top:0;right:-312px;width:20%;width:300px;height:100%;overflow-y:scroll;-webkit-transition:all .5s cubic-bezier(0.67, 0.01, 0.33, 0.99);-o-transition:all .5s cubic-bezier(0.67, 0.01, 0.33, 0.99);transition:all .5s cubic-bezier(0.67, 0.01, 0.33, 0.99)}.sentences-table *{margin:0;padding:0;font-family:inherit}.sentences-table .head{padding:12px;border-bottom: 2px solid #e8e8e8;font-weight: 500;user-select: none; width: 100%}.sentences-table .active > .head {font-weight: 700}.sentences-table .lang,.sentences-table .skill,.sentences-table .level,.sentences-table .lesson{-ms-flex-preferred-size:100%!important;flex-basis:100%!important;text-align:center;font-weight:700;background-color:#fff;-ms-flex-item-align:start;align-self:flex-start;cursor: pointer}.sentences-table.requested .head {cursor: default}.sentences-table .lesson > .sentence {display: -webkit-box;display: -ms-flexbox;display: flex;-ms-flex-wrap: wrap;flex-wrap: wrap}.sentences-table:not(.requested) .definition .sentence:not(:last-child) {border-bottom: 2px solid #e8e8e8}.sentences-table > .head.lesson{background-color: #f7f7f7}.sentences-table .sentenceHead{-ms-flex-preferred-size:100%;flex-basis:100%;font-weight:700;background-color:#f7f7f7;border-bottom:2px solid #e8e8e8}.sentences-table .sentencePair{width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-line-pack:stretch;align-content:stretch;padding:0}.sentences-table .definition{-ms-flex-preferred-size:50%;flex-basis:50%;-ms-flex-item-align:auto;-ms-grid-row-align:auto;align-self:auto;max-width:50%;padding:0;border-bottom:2px solid #e8e8e8;border-right:2px solid #e8e8e8}.sentences-table .definition > span:last-child{border:none}.sentences-table:not(.requested) .definition + .definition,.sentences-table.requested .definition{border-right:none}.sentences-table.requested .definition{display:-webkit-box;display:-ms-flexbox;display:flex}.practicesCounter{-ms-flex-preferred-size:60px;flex-basis:60px;color:#333;text-align:right;font-weight:700;cursor:help}.practicesCounter .indicator{display:inline-block;width:14px;height:14px;padding:0;margin-right:6px;margin-bottom:-1px;background-color:#e4e4e4;border-radius:50%}.red{background-color:#ff2828!important}.orange{background-color:#ff9600!important}.yellow{background-color:#ffc800!important}.sentences-button.green,.indicator.green{background-color:#78c800!important}.sentences-table.requested .sentencePair:last-child .definition{border-bottom:none}.sentences-table .definition .sentence {font-weight: normal}.sentences-table span{display:inline-block;width:100%;padding:10px 14px}.sentences-table span > span{display:inline;padding:0}.sentences-table .cat{padding:10px 12px!important;color:#5da90d;font-weight:700;background-color:#fff;border-bottom:2px solid #e8e8e8}.sentences-table .cat.user{color:#1caff6}.sentences-button{width:40px;height:40px;overflow:hidden;position:absolute;top:-5px;right:-5px;z-index:99;background-image:url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877498/dumbbell_lpkdnn.svg);background-color:#3eb1f6;background-position:center;background-repeat:no-repeat;background-size:50%;border-radius:50%;-webkit-box-shadow:0 0 0 5px #fff;box-shadow:0 0 0 5px #fff;-webkit-transition:all .3s ease-in-out;-o-transition:all .3s ease-in-out;transition:all .3s ease-in-out}.sentences-button:hover{background-color:#0083ff;-webkit-transform:translateY(-3px);-ms-transform:translateY(-3px);transform:translateY(-3px)}#showtable{width:60px;height:50px;padding-top:18px;padding-left:14px;position:fixed;top:44px;right:-10px;z-index:9999999;color:#fff;font-weight:bold;font-size:24px;/*border:2px solid #e5e5e5;*/border-right:none;border-radius:25px 0 0 25px;cursor:pointer;-webkit-transition: all .2s ease-in-out;-o-transition: all .2s ease-in-out;transition: all .2s ease-in-out;background: url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1569234432/left-arrow.svg) no-repeat 13px center, #1caff6;background-size: 26px;}#showtable:hover{background-color: #44c2ff;right: 0;opacity: .5}#showtable:hover + .sentences-table,.sentences-table:not(.requested):hover{-webkit-transform:translateX(-300px);-ms-transform:translateX(-300px);transform:translateX(-300px)}.dialog-wrap{cursor:pointer;-webkit-transition:all .35s ease-in-out;-o-transition:all .35s ease-in-out;transition:all .35s ease-in-out}.dialog-wrap.hidden{opacity:0;pointer-events:none}.dialog{cursor:default}.dialog ._3oZIl{margin-bottom:20px}.dialog ._1ixZq{min-width:100%;max-width:730px}#sentences-dialog .sentences-table.hidden{position:absolute;opacity:0;pointer-events:none}#sentences-dialog .levelGroup{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}#sentences-dialog .level{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:134px;height:180px;padding:10px;margin-right:15px;position:relative;color:#fff;text-align:center;background-color:#eee;border-radius:10px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}#sentences-dialog .level:last-of-type{margin-right:0}.level.level0{background-color:#ce81fe!important}.level.level1{background-color:#3eb0f6!important}.level.level2{background-color:#78c813!important}.level.level3{background-color:#ed4748!important}.level.level4{background-color:#f39531!important}.level.level5{color:#b36b03!important;background:-webkit-linear-gradient(315deg,#ffd900,#ffd900 26%,#ffc800 0,#ffc800 39%,#ffd900 0,#ffd900 52%,#ffc800 0,#ffc800 57%,#ffd900 0,#ffd900 78%,#ffc800 0,#ffc800 90%,#ffd900 0,#ffd900)!important;background:-o-linear-gradient(315deg,#ffd900,#ffd900 26%,#ffc800 0,#ffc800 39%,#ffd900 0,#ffd900 52%,#ffc800 0,#ffc800 57%,#ffd900 0,#ffd900 78%,#ffc800 0,#ffc800 90%,#ffd900 0,#ffd900)!important;background:linear-gradient(135deg,#ffd900,#ffd900 26%,#ffc800 0,#ffc800 39%,#ffd900 0,#ffd900 52%,#ffc800 0,#ffc800 57%,#ffd900 0,#ffd900 78%,#ffc800 0,#ffc800 90%,#ffd900 0,#ffd900)!important}.level > button{padding:7px 16px;margin-bottom:7px;color:inherit;background:transparent}.level > button:after{background-color:transparent;border-radius:8px;border-color:currentColor}.level .label{margin-top:6px;font-size:20px;font-weight:600}.level .digit{font-size:65px;font-weight:700;line-height:1em}.level .sentencesCount{margin-bottom:10px}.levelGroup.grid1 .level{width:156px!important}#startPracticeButton{width:100%;margin-top:20px;border-radius:10px}#startPracticeButton::after{border-radius:10px}#review-sentences-dialog-wrap{z-index:99999;background:transparent}.tick{width:30px;height:30px;position:absolute;top:-10px;right:-10px;background-color:#fdfdfd;border-radius:8px;border:2px solid #ededed;-webkit-box-shadow:0 0 0 5px #fff;box-shadow:0 0 0 5px #fff}.tick:after{content:"";display:block;width:15px;height:15px;position:absolute;top:6px;right:20%;background-color:#3eb0f6;border-radius:5px;opacity:0;-webkit-transition:all .1s ease-in-out;-o-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.level.on .tick:after,._1fneo.on .tick:after{opacity:1}._2albn .tick{width:40px;height:40px;top:-5px;right:-5px;z-index:99;border-width:4px;border-radius:50%}._2albn .tick:after{width:20px;height:20px;top:6px;right:6px;border-radius:50%;-webkit-transition:all .1s ease-in-out;-o-transition:all .1s ease-in-out;transition:all .1s ease-in-out}#translationExercise{width:100%;height:100%;max-width:unset!important;margin:0!important;position:fixed;left:0;top:0;z-index:999999;opacity:0;-webkit-transition:all .35s ease-in-out;-o-transition:all .35s ease-in-out;transition:all .35s ease-in-out;pointer-events:none;background-image:url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1561893199/confetti.gif);background-size:cover}#translationExercise::before{content:"Great job!";display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;height:100%;padding-bottom:45px;position:absolute;top:0;left:0;color:#fff;font-size:64px;text-align:center;font-weight:700;opacity:0;-webkit-transform:translateY(40px) scale(.9);-ms-transform:translateY(40px) scale(.9);transform:translateY(40px) scale(.9);-webkit-transition:opacity .5s cubic-bezier(0.51,0,0.53,0.99) .2s,-webkit-transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s;transition:opacity .5s cubic-bezier(0.51,0,0.53,0.99) .2s,-webkit-transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s;-o-transition:transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s,opacity .5s cubic-bezier(0.51,0,0.53,0.99) .2s;transition:transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s,opacity .5s cubic-bezier(0.51,0,0.53,0.99) .2s;transition:transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s,opacity .5s cubic-bezier(0.51,0,0.53,0.99) .2s,-webkit-transform .8s cubic-bezier(0.51,0,0.53,0.99) .2s}#translationExercise.phrase1::before{content:"Great job!"}#translationExercise.phrase2::before{content:"Nicely done!"}#translationExercise.phrase3::before{content:"Excellent!"}#translationExercise.phrase4::before{content:"Perfect!"}#translationExercise.phrase5::before{content:"Keep up the good work!"}#translationExercise.phrase6::before{content:"Impressive!"}#translationExercise.phrase7::before{content:"Splendid!"}#translationExercise.phrase8::before{content:"Awesome!"}#translationExercise.phrase9::before{content:"Fantastic!"}#translationExercise.phrase10::before{content:"Brilliant!"}#translationExercise.phrase11::before{content:"Amazing!"}#translationExercise.phrase12::before{content:"Oustanding!"}#translationExercise.phrase13::before{content:"Incredible!"}#translationExercise.finish::before{opacity:1;-webkit-transform:translateY(0) scale(1);-ms-transform:translateY(0) scale(1);transform:translateY(0) scale(1)}#translationExercise.finish ._3PBCS{opacity:0}._3PBCS{-webkit-transition:opacity .2s ease-in-out;-o-transition:opacity .2s ease-in-out;transition:opacity .2s ease-in-out}#translationExercise.shown{opacity:1;pointer-events:all}html.sentenceTraining{max-height:100%;overflow-y:scroll}html.sentenceTraining body{max-height:100%;overflow: hidden;}.buttonGroup{display:inline-block;margin-right:10px}.buttonGroup button:first-child,.buttonGroup button:first-child::after{border-top-right-radius:0;border-bottom-right-radius:0}.buttonGroup button:not(:first-child),.buttonGroup button:not(:first-child)::after{border-top-left-radius:0;border-bottom-left-radius:0}#translationExercise ._3P3SL{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}#translationExercise ._3P3SL h2{margin:0}#сorrect ._3P3SL h2{margin-left:10px;font-size:26px}#translationExercise ._2npwn{-webkit-box-align: center;-ms-flex-align: center;align-items: center}#endPractice{cursor:pointer}#headerContainer ._1533-{margin-right:45px}#TTSswitch{width:25px;height:25px;margin-top:-5px;position:absolute;right:40px;cursor:pointer;background-size:100%;background-repeat:no-repeat}#TTSswitch.on{background-image:url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1563040474/speaker_hw69cc.svg)}#TTSswitch.off{background-image:url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1563040474/speaker_off_yy1fmd.svg)}#TTSswitch:hover{opacity:.8}#translationExercise ._3GXmV{border:none;-webkit-box-shadow:0 2px 0 #e5e5e5 inset;box-shadow:0 2px 0 #e5e5e5 inset}.JotLT.progress{top:150%;color:#ccc!important}button.active{background:none;border-width:4px 0 0;border-radius:16px}button.active:after{bottom:0;border-width:0}.jJFkx ._75iiA{max-width:280px;line-height:1.4}.slidein{-webkit-animation-name:V;animation-name:V;opacity:0;-ms-transform:translateX(50px);-webkit-transform:translateX(50px);transform:translateX(50px)}.slideout{-webkit-animation-name:W;animation-name:W;opacity:1;-ms-transform:translateX(0);-webkit-transform:translateX(0);transform:translateX(0)}#globalPracticeModule{position:-webkit-sticky;position:sticky;top:-111px;z-index:99;-webkit-box-shadow:0 -26px 0 #fff;box-shadow:0 -26px 0 #fff;opacity:0;-webkit-transition:all .4s ease-in-out .5s,opacity .4s ease-in-out;-o-transition:all .4s ease-in-out .5s,opacity .4s ease-in-out;transition:all .4s ease-in-out .5s,opacity .4s ease-in-out}#globalPracticeModule.added{opacity:1;will-change:transform;-webkit-transition:all .4s ease-in-out,opacity .4s ease-in-out 0.5s,-webkit-transform .8s ease-in-out;transition:all .4s ease-in-out,opacity .4s ease-in-out 0.5s,-webkit-transform .8s ease-in-out;-o-transition:all .4s ease-in-out,opacity .4s ease-in-out 0.5s,transform .8s ease-in-out;transition:all .4s ease-in-out,opacity .4s ease-in-out 0.5s,transform .8s ease-in-out;transition:all .4s ease-in-out,opacity .4s ease-in-out 0.5s,transform .8s ease-in-out,-webkit-transform .8s ease-in-out}#globalPracticeModule.added + #otherModulesWrapper{-webkit-transform:translateY(204px);-ms-transform:translateY(204px);transform:translateY(204px);-webkit-transition:all .4s ease-in-out .8s,-webkit-transform .4s ease-in-out;transition:all .4s ease-in-out .8s,-webkit-transform .4s ease-in-out;-o-transition:all .4s ease-in-out .8s,transform .4s ease-in-out;transition:all .4s ease-in-out .8s,transform .4s ease-in-out;transition:all .4s ease-in-out .8s,transform .4s ease-in-out,-webkit-transform .4s ease-in-out}#globalPracticeModule.out{-webkit-transform:translate3d(0,204px,0);transform:translate3d(0,204px,0)}#otherModulesWrapper{width:100%;position:absolute;top:0;-webkit-transform-origin:top;-ms-transform-origin:top;transform-origin:top;-webkit-transition:all .4s ease-in-out .4s;-o-transition:all .4s ease-in-out .4s;transition:all .4s ease-in-out .4s}#globalPracticeModule ._1E3L7{position: relative}#otherModulesWrapper.commonDelay{-webkit-transition:all .4s ease-in-out .8s!important;-o-transition:all .4s ease-in-out .8s!important;transition:all .4s ease-in-out .8s!important}._2_lzu{position:relative}._2_lzu.stickyPracticeModule #otherModulesWrapper{opacity:.4;-webkit-filter:saturate(0);filter:saturate(0);pointer-events:none;-webkit-transform:translateY(204px) scale(.925)!important;-ms-transform:translateY(204px) scale(.925)!important;transform:translateY(204px) scale(.925)!important;-webkit-transition:all .4s ease-in-out!important;-o-transition:all .4s ease-in-out!important;transition:all .4s ease-in-out!important}.stickyPracticeModule #globalPracticeModule h2{margin-bottom:16px}.stickyPracticeModule ._1wiLJ{width:100%;margin-bottom:19px}.hint{width:280px;height:auto;padding:22px;text-align:center;white-space:normal}._2_lzu:not(.stickyPracticeModule) #hint-button ._3bFAF{left:-440%}.stickyPracticeModule #hint-button{display:none}#buttonWrap{display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}#buttonWrap > *{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}#buttonWrap ._35EBv{width:70px;margin:0;border-radius:16px}#buttonWrap ._35EBv:after {top: 9px;-webkit-transform: scale(.8);-ms-transform: scale(.8);transform: scale(.8);right: 0}#buttonWrap select{height:100%;padding-right:30px;font-weight:700}#startGlobalPracticeButton,#buttonWrap ._35EBv{margin-right:10px}#cancelPracticeButton{padding-bottom:7px}#cancelPracticeButton img{min-width:16px;min-height:16px;border:none;outline:none}[data-test="skill-tree"]{background-color:inherit}._2GJb6{background-color:inherit}._2GJb6,._2albn{position:relative}.skillOverlay{width:144px;height:167px;position:absolute;top:-22px;left:-19px;z-index:999;background-color:inherit;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;-webkit-transition:all .1s ease-in-out;-o-transition:all .1s ease-in-out;transition:all .1s ease-in-out}.skillOverlay:hover{opacity:.15}.skillOverlay:not([data-target-skill-index]){opacity:0!important;cursor:default}._2GJb6.skills-1 .skillOverlay.skill-1{left:calc((100% - 144px) / 2)}._2GJb6.skills-2 .skillOverlay.skill-1{left:calc((100% - (144px * 2)) / 2)}._2GJb6.skills-2 .skillOverlay.skill-2{right:calc((100% - (144px * 2)) / 2)}._2GJb6.skills-3 .skillOverlay.skill-1{left:calc((100% - (144px * 3)) / 2)}._2GJb6.skills-3 .skillOverlay.skill-2{left:calc((100% - 144px) / 2)}._2GJb6.skills-3 .skillOverlay.skill-3{right:calc((100% - (144px * 3)) / 2)}.filtered ._1fneo.no-sentences,.filtered ._1bcgw{-webkit-filter:saturate(0);filter:saturate(0);pointer-events:none}.filtered ._1fneo.no-sentences *,.filtered ._1bcgw *{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.filtered ._1fneo.no-sentences ._3hKMG{background:#e5e5e5!important}.filtered ._1fneo.no-sentences ._33VdW,.filtered ._1bcgw ._33VdW{color:#999!important}.filtered ._1fneo.no-sentences ._9l65a{background-image:url(https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877498/skills-gray_zk75zy.svg)!important}._1fneo.off,._1fneo.on{-webkit-transition:opacity .1s ease-in-out;-o-transition:opacity .1s ease-in-out;transition:opacity .1s ease-in-out}._1fneo.off .sentences-button,._1fneo.on .sentences-button{opacity:0}._1fneo.off .sentences-button{background-color:#999}._1fneo.off{opacity:.6}.filtered ._1bcgw ._2CkkF[src="//d35aaqx5ub95lt.cloudfront.net/images/checkpoint-gold-juicy.svg"]{-webkit-filter:contrast(1.4) opacity(0.8);filter:contrast(1.4) opacity(0.8)}._2hVT_{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}._2MGCg{max-height:100px!important}.BYr_J{min-width:80px;min-height:80px}embed,iframe{position:absolute;bottom:0;left:0;z-index:999999995;opacity:0;pointer-events:none}._31h5W{cursor: pointer}.EXkdH{z-index:100}#wrong .KekRP{grid-column: 1/3}#wrong ._1cw2r{grid-column: 3/6}.RaAbI{margin-top: 2px}body._3jZBz::-webkit-scrollbar-track, body._3jZBz::-webkit-scrollbar-corner{background: rgba(0, 0, 0, .05)}[data-key-hint]:before {content: attr(data-key-hint);position: absolute;top: -25px;left: 0;font-size: 14px;width: 100%;display: inline-block;text-align: center;opacity: 0;-webkit-transition: all .2s ease-in-out;-o-transition: all .2s ease-in-out;transition: all .2s ease-in-out; color: #afafaf; pointer-events: none;}[data-key-hint]:hover:before {opacity: .75}._2KlCX [data-key-hint]:before{color: #f95a66}._2PUh7[data-key-hint]:before {filter: saturate(1.4) opacity(.8) brightness(1.2)} ._1yRbM [data-key-hint]:before{color: #58a700}.sentences-table .lang:not(.active) > *:not(.head), .sentences-table .skill:not(.active) > *:not(.head), .sentences-table .level:not(.active) > *:not(.head), .sentences-table .lesson:not(.active) > *:not(.head), .sentences-table:not(.requested) .sentence:not(.active) > *:not(.head) {display: none}.sentences-table .lang > *:not(.head) {border-left: 6px solid #3eb1f6;}.sentences-table .skill > *:not(.head) {border-left: 6px solid #ed4748}.sentences-table .level > *:not(.head) {border-left: 6px solid #fac833}.sentences-table .lesson > *:not(.head) {border-left: 6px solid #77c913}.sentences-table .sentence > *:not(.head):nth-of-type(2n) {border-left: 6px solid #cedde8}.sentences-table .lang .head:before, .sentences-table .skill .head:before, .sentences-table .level .head:before, .sentences-table .lesson .head:before, .sentences-table .sentence .head:before {content: "";display: inline-block;margin-right: 6px;width: 0;height: 0;border-style: solid;border-width: 5px 0 5px 6px;border-color: transparent transparent transparent #5da90d; -webkit-transition: all .2s ease-in-out;-o-transition: all .2s ease-in-out;transition: all .2s ease-in-out}.sentences-table .active > .head:before {-webkit-transform: rotate(90deg);-ms-transform: rotate(90deg);transform: rotate(90deg)}.lang > .head::before {border-left-color: #3fb1f6 !important}.skill > .head::before {border-left-color: #ed4748 !important}.level > .head::before {border-left-color: #fac833 !important}.lesson > .head::before {border-left-color: #77ca13 !important}.sentence > .head::before {border-left-color: #cedde8 !important}#deselectAll {color: #d2d2d2;font-weight: bold;cursor: pointer;position: absolute;top: 25px;right: 25px;border-bottom: 1px dashed rgba(0,0,0,.1)}'); const practiceHTMLTemplate = '<div class="BWibf _3MLiB" id="translationExercise"><div class="_3PBCS"><div class="_3giip"><div class="DdXah"><div class="Mlxjr" id="headerContainer"><div class="_38taa _2Zfkq cCL9P" id="endPractice"></div></div></div><div class="_2-1wu" id="moduleContainer"></div><div class="_3gDW-" id="controlsArea"></div></div></div></div>', challengeTemplate = '<div class="_14lWn _14lWn LjoXe _1VPue _1sKP2" id="challenge"><div data-test="challenge challenge-translate" class="_1Y5M_ _2szQy"><div class="_1ttrU Au17D _2CBTu"><h1 data-test="challenge-header" class="_1Zqmf"><span id="writeThis">Write this in your target language</span></h1><div class="_1gcJT"><div data-test="challenge-translate-prompt" class="_3VFHG" dir="ltr"><span data-test="hint-sentence" class="oR3Zt" id="nativeSentence"></span></div><div class="_23gwq"><div class="_2hVT_"><textarea data-test="challenge-translate-input" id="targetInput" autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" class="_2MGCg _1py6s _1e69E _3_NyK _1Juqt" data-gramm="false" dir="ltr" lang="fr" placeholder="Type in your target language"></textarea></div></div></div></div></div></div>', welcomeTemplate = '<div class="bs5Kw"><div class="_1pmjQ"><span class="_1Qxn8 _3xN8H _1-ph4"></span></div><div class="MXDj9"><h2 class="nyHZG">Practice writing in your target language!</h2><p class="_2w5q7">Translation into your target language is the best way to improve your language skills</p></div></div>', globalWelcomeTemplate = '<div class="bs5Kw"><div class="_1pmjQ"><span class="_1Qxn8 _3xN8H _1-ph4"></span></div><div class="MXDj9"><h2 class="nyHZG">Selective practice!</h2><p class="_2w5q7">Selective practice is a mode that makes it possible to practice sentences of all or certain skills you\'ve developed in the process of learning <b>' + getCourseInfo('learningLanguageName', true) + '</b> while using the script.<br><br><!--The mode is highly recommended for advanced learners as it demands using one\'s target language on quite an advanced level ;)<br><br>--><b>Good luck!</b></p></div></div>', practiceStartTemplate = '<div class="_3GXmV _1sntG"><div class="_1_XY0 _3wVKa"><div class="_1l6NK"></div><div class="_3rReK"></div><div class="_1cw2r"><button id="continueButton" data-test="player-next" data-key-hint="↵ Enter" class="_3_pD1 _2ESN4 _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _2L5kw _3Ry1f">Start practice</button></div></div></div>', practiceHeadTemplate = '<div class="_38taa _2Zfkq cCL9P" id="endPractice"></div><div id="TTSswitch"></div><div class="_3exN9"><div class="_1533-"><div class="MAF30"><div class="_1TkZD" id="progressBar" style="opacity: 0; width: 0%;"></div></div></div></div>', practiceCheckTemplate = '<div class="_3GXmV _1sntG"><div class="_1_XY0 _3wVKa"><div class="_1l6NK"><button data-test="player-skip" id="skipSentence" class="_3N_rN oNqWF _3hso2 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _2PUh7 H7AnT _3Ry1f" data-key-hint="⭾ Tab">Skip</button></div><div class="_1cw2r"><button id="continueButton" data-test="player-next" data-key-hint="↵ Enter" class="cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f" disabled="">Check</button></div></div></div>', practiceCorrectTemplate = '<div class="_2f9Fr _1sntG _1yRbM" id="correct"><div class="_1_XY0 _3wVKa"><div class="KekRP _3Txod _1yRbM"><div class="_2npwn"><div class="BYr_J _3nzjY"><span class="_3ze-9 _2dy4d cCL9P"></span></div><div class="_3P3SL"><div><h2 class="_3H0e2 _28jVs" id="youAreCorrect">You are correct</h2></div></div></div></div><div class="_1cw2r"><button id="continueButton" data-test="player-next" data-key-hint="↵ Enter" class="cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f _2VaJD _23-CV _2arQ0 _2vmUZ _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz mucpb">Continue</button></div></div></div>', practiceWrongTemplate = '<div class="_2f9Fr _1sntG _2KlCX" id="wrong"><div class="_1_XY0 _3wVKa"><div class="KekRP _3Txod _2KlCX"><div class="_2npwn"><div class="BYr_J _3nzjY"><span class="_1jIvO _23CAe cCL9P"></span></div><div class="_3P3SL"><div><h2 class="jJFkx _28jVs">Correct solution:<div class="_75iiA"><span><span id="correctSolution"></span></span></div></h2></div></div></div></div><div class="_1cw2r"><div class="buttonGroup"><button id="iMistypedButton" data-key-hint="* Ctrl" class="oNqWF _3hso2 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _3Ry1f _1AM95 _2PUh7 H7AnT">I mistyped</button><button id="iWasRightButton" data-test="player-next" data-key-hint="_ Space" class="cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f _2VaJD _23-CV _2arQ0 _2vmUZ _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz mucpb">Remember my answer</button></div><button id="continueButton" data-test="player-next" data-key-hint="↵ Enter" class="cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f _1rz1x">Continue</button></div></div></div>', audioTemplate = '<audio id="successSound"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1555571639/DuolingoSuccessOGG.ogg" type="audio/ogg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1559766656/DuolingoSuccessMP3.mp3" type="audio/mpeg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1555571640/DuolingoSuccessWAV.wav" type="audio/wav"></audio><audio id="wrongSound"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561060600/DuolingoWrongOGG.ogg" type="audio/ogg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561060600/DuolingoWrongMP3.mp3" type="audio/mpeg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561060601/DuolingoWrongWAV.wav" type="audio/wav"></audio><audio id="lessonCompleted"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561182188/DuolingoCompleteOGG.ogg" type="audio/ogg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561182188/DuolingoCompleteMP3.mp3" type="audio/mpeg"><source src="https://res.cloudinary.com/dn6n8yqqh/video/upload/v1561182191/DuolingoCompleteWAV.wav" type="audio/wav"></audio>', globalPracticeModuleTemplate = '<div id="globalPracticeModule"><div class="_2SCNP _1E3L7"><div class="_1kJVj"><div class="_3GEdB"><h2 id="globalPracticeModuleTitle">Practice translation into your target language</h2><div class="RaAbI" id="hint-button"><img class="_31h5W" src="https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877673/icon_info_e8pxr4.svg"></div></div></div><div id="buttonWrap"></div></div></div>', chooseSkillsButtonTemplate = '<button class="TbLPl cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _1g2dF _2VaJD _23-CV _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _1LsmY" id="chooseSkillsButton">Choose skills for practice</button>', hintTemplate = '<div class="_2nhHI _3ZTEO" style="z-index: 1;"><div class="_3h4O4" style="z-index: 2;"><div class="_1qcTI" style="z-index: 2;"></div></div><div class="_3bFAF" style="z-index: 1;"><div class="_11Xk2 hint">You\'d fancy practicing certain skills rather than an individual skill? Click the button to pick the skills for practice or practice them all at once!</div></div></div>', startPracticeTemplate = '<div class="_1wiLJ">...and set amount of sentences for practice</div><label class="_35EBv" title="Amount of sentences for practice"><select type="select" id="questionsQuantity"><option value="20">20</option><option value="30">30</option><option value="40" selected="selected">40</option><option value="50">50</option><option value="60">60</option><option value="70">70</option><option value="80">80</option><option value="90">90</option><option value="100">100</option></select></label><button id="startGlobalPracticeButton" class="cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f _2VaJD _23-CV _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr">Start practice</button><button id="cancelPracticeButton" class="oNqWF _3hso2 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _2PUh7 H7AnT"><img src="https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877714/x_sq1jmd.svg"></button><span id="deselectAll">Deselect all</span>'; // SHORTCUTS var body = document.body; function setStorageItm(prop, val) { localStorage.setItem(prop, val); } function getStorageItm(prop) { return localStorage.getItem(prop); } function removeElement(element) { element.parentNode.removeChild(element); } function getById(id) { return document.getElementById(id); } function firstOfSelector(selector) { return document.querySelector(selector); } function allOfSelector(selector) { return document.querySelectorAll(selector); } function includeInBody(html) { body.insertAdjacentHTML('afterbegin', html); } function addTemporaryStyle(styleId,style) { body.insertAdjacentHTML('afterbegin','<style id="' + styleId + '">' + style + '</style>'); } function removeTemporaryStyle(styleId) { removeElement(getById(styleId)); } function scrollTo(element, margintop) { window.scroll({ top: element.getBoundingClientRect().top + (window.scrollY === undefined ? window.scrollY : window.pageYOffset) - margintop, behavior: 'smooth' }); } // INFO FUNCTIONS var parsedDuoState; function updateParsedDuoState() { parsedDuoState = JSON.parse(getStorageItm("duo.state")); } function getSkillName() { var h = window.location.href; return (/[\/]([^\/]+?)[\/]([\w\d\-]+)$/g.test(h) ? /[\/]([^\/]+?)[\/]([\w\d\-]+)$/g.exec(h)[1] : null); } function getLessonIndex() { var h = window.location.href; return (/[\/]([^\/]+?)[\/]([\w\d\-]+)$/g.test(h) ? /[\/]([^\/]+?)[\/]([\w\d\-]+)$/g.exec(h)[2] : null); } function getCourseInfo(prop, refresh) { if (prop == 'courseId' || refresh) { updateParsedDuoState(); } return (prop !== 'learningLanguageName' ? parsedDuoState.user[prop] : parsedDuoState.courses[getCourseInfo('courseId')].title); } function getSkillsForCurrentLanguage() { var initArray = parsedDuoState.skills, keys = Object.keys(initArray), initArrayLength = keys.length, returnArray = [], wasFound = false, currentCourse = getCourseInfo('learningLanguage'); shortNamesArray = []; for (var i = initArrayLength - 1; i >= 0; i--) { var skill = initArray[keys[i]]; if (skill.learningLanguage == currentCourse) { wasFound = true; if (skill.accessible == true) { returnArray.push({shortName : skill.shortName, urlName : skill.urlName, level : skill.finishedLevels}); var shortNameIndex = shortNamesArray.indexOf(skill.shortName); if (shortNameIndex == -1) { shortNamesArray.push(skill.shortName); shortNamesArray.push([skill.urlName]); } else shortNamesArray[shortNameIndex + 1].push(skill.urlName); } } else if (wasFound) break; } return returnArray; } function getLevelOfSkill(urlName) { var skillsArrayLen = skillsArray.length; for (var i = 0; i < skillsArrayLen; i++) { var skill = skillsArray[i]; if (skill.urlName == urlName) return skill.level; } return null; } function getURLNameByShortName(shortName, index) { return shortNamesArray[shortNamesArray.indexOf(shortName) + 1][index]; } // RANDOM function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; } // EQUALIZE function equalizeString(string, saveAccents) { var replaceWith = '', reconstructionArray = [], replaceArray = [[/[\u0020][.?!]$/g, ''], [/[.?!]$/g, ''], [/-/g, ' '], [/[¿]/g, ''], [/[¡]/g, ''], [/[。!?]$/g, ''], [/[\u0020]$/g, ''], [/^[\u0020]/g, ''], [/[\/:]/g, ''], [/[\u0020][\u0020]/g, ' '], [/[,][\u0020]/g, ' '], [/[、]/g, ''], [/[:]/g, ''], [/[æ]/g, 'ae'], [/[ø]/g, 'oe'], [/[å]/g, 'aa'], [/[ß]/g, 'ss'], [/[œ]/g, 'oe'], [/[ñ]/g, 'n\''], [/[dž]/g, 'dzh'], [/[ĉ]/g, 'cx'], [/[ĝ]/g, 'gx']]; function registerOffset(match, offset) { reconstructionArray.push([match,offset,replaceWith.length]); return replaceWith; } var replaceArrayLen = replaceArray.length; for (var replace = 0; replace < replaceArrayLen; replace++) { replaceWith = replaceArray[replace][1]; string = string.replace(replaceArray[replace][0],registerOffset); } if (saveAccents) return [string,reconstructionArray]; return string.toLowerCase() .normalize('NFD') .replace(/[\u0300-\u036f]/g, "") .replace(/[\u0591-\u05C7]/g, ''); } function equalizeArray(arr) { arr = arr.flat(5); var arrlen = arr.length; for (var i = 0; i < arrlen; i++) arr[i] = equalizeString(arr[i], false); return arr; } // ARRAYS function shuffleArray(arr) { var currentIndex = arr.length, temporaryValue, randomIndex; while (0 !== currentIndex) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex -= 1; temporaryValue = arr[currentIndex]; arr[currentIndex] = arr[randomIndex]; arr[randomIndex] = temporaryValue; } return arr; } function getNames(arr) { var returnarr = [], arrlen = arr.length; for (var i = 0; i < arrlen; i++) returnarr.push(arr[i][0]); return returnarr; } function makeSeparate(arr) { var returnarr = [], arrlen = arr.length; for (var i = 0; i < arrlen; i++) returnarr.push([arr[i]]); return returnarr; } // PRACTICE function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); } function inheritFormatting(byDuo, byUser) { if (!(/[\u0020][.?!]$/g).test(byUser) && (/[\u0020][.?!]$/g).test(byDuo)) byUser += (/([\u0020][.?!])$/g).exec(byDuo)[1]; else if (!(/[.?!]$/g).test(byUser) && (/[.?!]$/g).test(byDuo)) byUser += (/([.?!])$/g).exec(byDuo)[1]; if (byDuo.charAt(0) == byDuo.charAt(0).toUpperCase()) byUser = capitalizeFirstLetter(byUser); return byUser; } function generateQuestions(skillsarray, amountofquestions){ function getMainSentence(skill, level, lesson, sentence, n1) { var sentencePairArray = skillsarray[skill][1][level][1][lesson][1][sentence][n1]; if (sentencePairArray[0].length > 0) return shuffleArray(sentencePairArray[0])[0]; else return shuffleArray(sentencePairArray[1])[0]; } var commonArray = [], skillsArrayLen = skillsarray.length, maxSentencesPerSkill = Math.ceil(amountofquestions / skillsArrayLen); for (var skill = 0; skill < skillsArrayLen; skill++) { var skillSentences = [], levels = skillsarray[skill][1], levelsarrayLen = levels.length; for (var level = 0; level < levelsarrayLen; level++) { var lessons = levels[level][1]; lessonsarrayLen = lessons.length; for (var lesson = 0; lesson < lessonsarrayLen; lesson++) { var sentences = lessons[lesson][1], sentencesarrayLen = sentences.length; for (var sentence = 0; sentence < sentencesarrayLen; sentence++) { skillSentences.push([getMainSentence(skill, level, lesson, sentence, 0), // main target sentence [0] getMainSentence(skill, level, lesson, sentence, 1), // main native sentence [1] sentences[sentence][0], // array of target sentences [2] skillsarray[skill][0], // skill name [3] levels[level][0], // level [4] lessons[lesson][0], // lesson name [5] sentence, // sentence index [6] sentences[sentence][2]]); // how many times the sentence pair was practiced [7] } } } skillSentences.sort(function(a,b){ if (a[7] > b[7]) return 1; else if (a[7] < b[7]) return -1; else return 0; }); commonArray = commonArray.concat(skillSentences.slice(0, maxSentencesPerSkill)); } var x = 1; while (commonArray.length > amountofquestions) { commonArray.splice(((maxSentencesPerSkill * x) - (x - 1)) - 1, 1); x++; } return shuffleArray(commonArray); } function playTTS(lang,sentence) { if (!unavailableForTTS.includes(lang)) { var iFrame = getById('ttsiframe'), iFrameBody; iFrame.removeAttribute('sandbox'); if (iFrame.contentDocument) iFrameBody = iFrame.contentDocument.getElementsByTagName('body')[0]; else if (iFrame.contentWindow) iFrameBody = iFrame.contentWindow.document.getElementsByTagName('body')[0]; else iFrameBody = iFrame.contentDocument.body; var link = 'https://translate.google.com/translate_tts?ie=UTF-8&client=tw-ob&tl=' + lang + '&q=' + sentence.replace(/\u0020/g,'+').replace(/[.]/g,'') + '&rd=' + getRandomInt(1,50000000); iFrameBody.innerHTML = '<video name="media" controls="" autoplay=""><source src="' + link + '" type="audio/mpeg"></video>'; iFrame.setAttribute('sandbox',''); } } function setStreak(streak, current, from) { var bar = getById('progressBar'); switch (streak) { case 0: case 1: case 2: bar.className = '_1TkZD'; break; case 3: bar.className = '_1TkZD _3CfOD'; break; case 4: bar.className = '_1TkZD _1Ev8g'; break; default: bar.className = '_1TkZD _2R430'; break; } if (streak > 1) bar.insertAdjacentHTML('afterbegin','<div class="JotLT">' + streak + ' IN A ROW</div>'); else if (!!(label = bar.querySelectorAll('.JotLT')[0])) removeElement(label); bar.insertAdjacentHTML('afterbegin','<div class="JotLT progress">' + current + '/' + from + '</div>'); } // DEFAULTS var duosentences = [], keyboardDefined = false, substituted = false, skillsArray = getSkillsForCurrentLanguage(), shortNamesArray = [], isPractice = false, unavailableForTTS = ['cy','sw','hw','he','hv','nv','tlh','ga'], thisSentencesButton, ttsEnabled = true; updateParsedDuoState(); // STORAGE function updateDuoSentencesArray() { setStorageItm('duosentences', JSON.stringify(duosentences)); } if (!!getStorageItm('duosentences')) duosentences = JSON.parse(getStorageItm('duosentences')); // RESETS THE SENTENCES: BE CAREFUL // if (!!getStorageItm('duosentences')) localStorage.removeItem('duosentences'); if (getStorageItm('keyboard')) keyboardDefined = true; if (!!getStorageItm('ttsEnabled')) ttsEnabled = JSON.parse(getStorageItm('ttsEnabled')); else setStorageItm('ttsEnabled', JSON.stringify(true)); if (!getStorageItm('introShown')) { setTimeout(function(){ showIntroDialog(); }, 2000); setStorageItm('introShown', JSON.stringify(true)); } // LAYOUT if (getLessonIndex() == 'translation-practice') { substituted = true; var skillName = getSkillName(); startPractice([[skillName, arrayRequest(getCourseInfo('courseId'), skillName)]], skillName, 20); } else if (/\.com\/global\-practice$/g.test(window.location.href)) { substituted = true; startPractice(arrayRequest(getCourseInfo('courseId')), 'global', 40); } includeInBody(audioTemplate); includeInBody('<iframe id="ttsiframe" allow="autoplay"></iframe>'); body.classList.add("_3jZBz"); function updateTable() { var existingTable = getById('table-wrap'); if (!!existingTable) removeElement(existingTable); includeInBody(getEntireTableHTMLLayout()); allOfSelector(".sentences-table .lang .head, .sentences-table .skill .head, .sentences-table .level .head, .sentences-table .lesson .head, .sentences-table .sentence .head").forEach(function(element){ element.onclick = function(event){ event.stopPropagation(); this.parentNode.classList.toggle("active"); } }); } function wrap(elementsArray, wrapper) { elementsArray[0].parentNode.insertBefore(wrapper, elementsArray[0]); for (var i = 0; i < elementsArray.length; i++) wrapper.appendChild(elementsArray[i]); } function updateTransform() { var mod = getById('globalPracticeModule'); if (window.pageYOffset > 204) mod.classList.add('out'); else mod.classList.remove('out'); } async function addChecksToSkills() { var initialText = this.innerText; this.innerText = 'Please wait...'; this.disabled = true; addTemporaryStyle('cursorProgress', '* { cursor: progress !important; }'); setTimeout(function(){ function whichChild(elem) { var i = 0; while ((elem = elem.previousElementSibling) != null) ++i; return i; } firstOfSelector('[data-test="skill-tree"]').classList.add('filtered'); var skillsCollection = allOfSelector('._33VdW:not(.AlP1u):not(._1Zjfp):not([data-skill-url-name="no-sentences"])'), len = skillsCollection.length; for (var i = 0; i < len; i++) { var skill = skillsCollection[i], skillElement = skill.parentNode.parentNode.parentNode, skillsContainer = skillElement.parentNode, childIndex = whichChild(skillElement); skillsContainer.classList.add('skills-' + skillsContainer.querySelectorAll('._1fneo').length); skillsContainer.insertAdjacentHTML('beforeend','<div class="skillOverlay skill-' + (childIndex + 1) + '"></div>'); var skillOverlaysList = skillsContainer.querySelectorAll('.skillOverlay'); skillOverlaysList[skillOverlaysList.length - 1].setAttribute('data-target-skill-index', childIndex); skillOverlaysList[skillOverlaysList.length - 1].addEventListener('click', function(){ var correspondingSkill = this.parentNode.querySelectorAll('._1fneo')[parseInt(this.getAttribute('data-target-skill-index'))]; if (correspondingSkill.classList.contains('on')) correspondingSkill.classList.replace('on','off'); else correspondingSkill.classList.replace('off','on'); var startbutton = getById('startGlobalPracticeButton'); if (allOfSelector('._1fneo.on').length == 0) startbutton.disabled = true; else startbutton.disabled = false; }); skill.parentNode.parentNode.insertAdjacentHTML('afterbegin','<div class="tick"></div>'); skillElement.classList.add('on'); } var buttonsCollection = allOfSelector('.sentences-button'), len2 = buttonsCollection.length; for (var i = 0; i < len2; i++) { buttonsCollection[i].onclick = function(event){ event.stopPropagation(); createTrainingDialog(this.getAttribute('data-sentences-skill-name')); }; } firstOfSelector('._2_lzu').classList.add('stickyPracticeModule'); window.addEventListener('scroll', updateTransform); firstOfSelector('._2_lzu').style.height = firstOfSelector('._3MT-S').offsetHeight + "px"; removeTemporaryStyle('cursorProgress'); getById('buttonWrap').innerHTML = startPracticeTemplate; getById('globalPracticeModuleTitle').innerText = 'Pick the skills...'; function cancelPractice() { firstOfSelector('[data-test="skill-tree"]').classList.remove('filtered'); firstOfSelector('._2_lzu').classList.remove('stickyPracticeModule'); getById('otherModulesWrapper').classList.add('commonDelay'); setTimeout(function(){ getById('otherModulesWrapper').classList.remove('commonDelay'); }, 1000); window.removeEventListener('scroll', updateTransform); getById('globalPracticeModule').classList.remove('out'); getById('globalPracticeModuleTitle').innerText = 'Practice translation into your target language'; getById('buttonWrap').innerHTML = chooseSkillsButtonTemplate; getById('chooseSkillsButton').addEventListener('click', addChecksToSkills); for (var i = 0; i < len; i++) { var skill = skillsCollection[i], skillElement = skill.parentNode.parentNode.parentNode, skillsContainer = skillElement.parentNode; skillsContainer.className = skillsContainer.className.replace(/\u0020skills-[\d]/g,''); var skillOverlaysList = skillsContainer.querySelectorAll('.skillOverlay'); removeElement(skillOverlaysList[skillOverlaysList.length - 1]); skillElement.className = '_1fneo'; var tick = skillElement.querySelectorAll('.tick')[0]; if (!!tick) removeElement(tick); } } getById('cancelPracticeButton').addEventListener('click', cancelPractice); getById('deselectAll').addEventListener('click', function(){ allOfSelector('._1fneo.on').forEach(function(skill){ skill.classList.replace("on","off"); }); getById('startGlobalPracticeButton').disabled = "true"; }); getById('startGlobalPracticeButton').addEventListener('click', function(){ var selectedSkillsCollection = allOfSelector('._1fneo.on'), selectedSkillsLen = selectedSkillsCollection.length, globalPracticeSkills = [], currentCourse = getCourseInfo('courseId'); for (var i = 0; i < selectedSkillsLen; i++) { var skillName = selectedSkillsCollection[i].querySelectorAll('._33VdW')[0].getAttribute('data-skill-url-name'); globalPracticeSkills.push([skillName, arrayRequest(currentCourse, skillName)]); } startPractice(globalPracticeSkills, 'global', parseInt(getById('questionsQuantity').value)); setTimeout(function(){ document.getElementsByTagName('html')[0].classList.add('sentenceTraining'); cancelPractice(); }, 1000); }); setTimeout(function(){ if (!!(firstAvailableSkill = firstOfSelector('._1fneo.on'))) scrollTo(firstAvailableSkill, 200); },600); },200); } function createGlobalPracticeButton() { var divsInSidebar = allOfSelector('._2_lzu > div'), wrapper = document.createElement('div'); wrapper.id = 'otherModulesWrapper'; if (divsInSidebar.length > 1) wrap(divsInSidebar, wrapper); firstOfSelector('._2_lzu').insertAdjacentHTML('afterbegin', globalPracticeModuleTemplate); setTimeout(function(){ getById('globalPracticeModule').classList.add('added'); },50); getById('buttonWrap').innerHTML = chooseSkillsButtonTemplate; // function showHint(event) { // event.stopPropagation(); // this.insertAdjacentHTML('afterbegin',hintTemplate); // this.addEventListener('click', hideHint); // function hideHint() { // var hintButton = getById('hint-button'); // if (!!hintButton) { // var hintText = hintButton.querySelectorAll('._2nhHI._3ZTEO')[0]; // if (!!hintText) { // removeElement(hintText); // hintButton.querySelectorAll('._31h5W')[0].setAttribute('src','https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877673/icon_info_e8pxr4.svg'); // } // hintButton.removeEventListener('click', hideHint); // hintButton.addEventListener('click', showHint); // } // body.removeEventListener('click', hideHint); // } // body.addEventListener('click', hideHint); // this.removeEventListener('click', showHint); // this.querySelectorAll('._31h5W')[0].setAttribute('src','https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877798/icon_info_dark_qhc3wz.svg'); // } getById('hint-button').addEventListener('click', showIntroDialog); getById('chooseSkillsButton').addEventListener('click', addChecksToSkills); } function removePracticeModule(smooth){ if (!!(practiceModule = getById('globalPracticeModule'))) { if (smooth) { practiceModule.classList.remove('added'); setTimeout(function(){ if(!!getById('globalPracticeModule')) removeElement(practiceModule); firstOfSelector('._2_lzu').classList.remove('stickyPracticeModule'); },900); } else removeElement(practiceModule); } } function createDialog(title, contents){ includeInBody('<div class="BKNBq _1CJpK _1AbdB dialog-wrap" id="custom-dialog-wrap"><div id="custom-dialog" class="_1bYPb _3gvMn _3I5-U _2CNG0 _2-QsC dialog" tabindex="-1" role="dialog" onclick="event.stopPropagation()"><div class="_1ePWu" id="dialog-close"><img src="https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877714/x_sq1jmd.svg"></div><div class="_1ixZq"><h1 class="_3oZIl">' + title + '</h1>' + contents + '</div></div></div>'); var dialogWrap = getById('custom-dialog-wrap'); function closeDialog() { dialogWrap.classList.add('hidden'); setTimeout(function(){ removeElement(dialogWrap); }, 500); } getById('dialog-close').addEventListener('click',closeDialog); dialogWrap.addEventListener('click',closeDialog); } function showIntroDialog() { createDialog('Welcome to DuoWriter!', '<p><b>DuoWriter</b> is a userscript that <b>collects</b> the sentences you meet while learning on Duolingo to give you a chance to <b>practice writing</b> in your target language. You can choose an individual skill or a collection of skills for practice — we all have been missing a global practice mode, haven\'t we?</p><p><b>Press a practice button</b> next to the skill to start practicing its sentences; press «<b>Choose skills for practice</b>» button to choose the skills you want to practice in a bunch. Do not forget to set the amount of sentences for practice :)</p><p>Sentences of every skill have their own level that depends on how many times you have practiced that particular sentence. Skill level indicates an average percentage of your proficiency in its sentences (<b>hover</b> over a practice button to see the percentage):</p><p><b style="color: #3eb1f6">• Blue</b>: <b>0%</b> proficiency<br><b style="color: #ff2828">• Red</b>: from <b>0%</b> to <b>25%</b> proficiency<br><b style="color: #ff9600">• Orange</b>: from <b>25%</b> to <b>50%</b> proficiency<br><b style="color: #ffc800">• Yellow</b>: from <b>50%</b> to <b>80%</b> proficiency<br><b style="color: #78c800">• Green</b>: from <b>80%</b> to <b>100%</b> proficiency</p>'); } // WORK WITH DUOSENTENCES ARRAY function addOpposite(isByDuo, comparedString, cat, sentences, sentence) { var category = sentences[sentence][cat]; if (isByDuo) { if (equalizeArray(category).includes(equalizeString(comparedString, false))) { if (!equalizeArray(category[0]).includes(equalizeString(comparedString, false))) category[0].push(comparedString); } else category[0].push(comparedString); } else if (!equalizeArray(category).includes(equalizeString(comparedString, false))) category[1].push(comparedString); return true; } function search(isByDuo1, isByDuo2, cat1, cat2, num1, num2, sentences, sentence) { var num1arr = sentences[sentence][num1]; if (isByDuo1) { if (equalizeArray(num1arr).includes(equalizeString(cat1, false))) { if (!equalizeArray(num1arr[0]).includes(equalizeString(cat1, false))) num1arr[0].push(cat1); return addOpposite(isByDuo2, cat2, num2, sentences, sentence); } } else if (equalizeArray(num1arr).includes(equalizeString(cat1, false))) return addOpposite(isByDuo2, cat2, num2, sentences, sentence); return false; } function addSentences(courseName, skillName, skillLevel, lessonNumber, TL, NL, TLDuo, NLDuo) { console.log("Target Sentence: " + TL); console.log("Native Sentence: " + NL); console.log("————————————————————"); var sentenceArray = [[[],[]],[[],[]]]; if (TLDuo) sentenceArray[0][0].push(TL); else sentenceArray[0][1].push(TL); if (NLDuo) sentenceArray[1][0].push(NL); else sentenceArray[1][1].push(NL); sentenceArray.push(0); if ((course = getNames(duosentences).indexOf(courseName)) !== -1) { var skills = duosentences[course][1]; if ((skill = getNames(skills).indexOf(skillName)) !== -1) { var levels = skills[skill][1], alreadyExists = false; levels.forEach(function(level){ level[1].forEach(function(lesson){ var sentences = lesson[1]; sentences.forEach(function(sentence, sentenceIndex){ if (!alreadyExists) { alreadyExists = search(TLDuo, NLDuo, TL, NL, 0, 1, sentences, sentenceIndex); if (!alreadyExists) alreadyExists = search(NLDuo, TLDuo, NL, TL, 1, 0, sentences, sentenceIndex); } }); }); }); if (!alreadyExists) { if ((level = getNames(levels).indexOf(skillLevel)) !== -1) { var lessons = levels[level][1]; if ((lesson = getNames(lessons).indexOf(lessonNumber)) !== -1) { var sentences = lessons[lesson][1]; sentences.push(sentenceArray); } else lessons.push([lessonNumber,[sentenceArray]]); } else levels.push([skillLevel,[[lessonNumber,[sentenceArray]]]]); console.log("New sentence"); } else { console.log("Already exists"); } } else skills.push([skillName,[[skillLevel,[[lessonNumber,[sentenceArray]]]]]]); } else duosentences.push([courseName,[[skillName,[[skillLevel,[[lessonNumber,[sentenceArray]]]]]]]]); updateDuoSentencesArray(); updateTable(); } function arrayRequest(courseName, skillName, skillLevel, lessonNumber, sentenceNumber) { var len1 = duosentences.length; for (var course = 0; course < len1; course++) { var thisCourse = duosentences[course]; if (thisCourse[0] == courseName) { if (skillName == undefined) return thisCourse[1]; var len2 = thisCourse[1].length; for (var skill = 0; skill < len2; skill++) { var thisSkill = thisCourse[1][skill]; if (thisSkill[0] == skillName) { if (skillLevel == undefined) return thisSkill[1]; var len3 = thisSkill[1].length for (var level = 0; level < len3; level++) { var thisLevel = thisSkill[1][level]; if (thisLevel[0] == skillLevel) { if (lessonNumber == undefined) return thisLevel[1]; var len4 = thisLevel[1].length; for (var lesson = 0; lesson < len4; lesson++) { var thisLesson = thisLevel[1][lesson]; if (thisLesson[0] == lessonNumber) { if (sentenceNumber == undefined) return thisLesson[1]; var len5 = thisLesson[1].length; for (var sentence = 0; sentence < len5; sentence++) { var thisSentence = thisLesson[1][sentence]; if (sentence == sentenceNumber) { thisSentence[2]++; updateDuoSentencesArray(); updateTable(); } else if (sentence == len5 - 1) return false; } } else if (lesson == len4 - 1) return false; } } else if (level == len3 - 1) return false; } } else if (skill == len2 - 1) return false; } } else if (course == len1 - 1) return false; } } function getMarkInfo(n) { switch (n) { case 0: return ['','You haven\'t practiced this sentence pair yet :(']; default: return ['green','Excellent! You have successfully practiced this sentence pair ' + n + ' times']; } } // case 1: return ['red','This sentence pair needs more attention — it\'s been practiced correctly only ' + n + ' time' + (n > 1 ? 's' : '') + ' so far :(']; // case 2: return ['orange','Looks better — you\'re on your way! This sentence pair has been practiced correctly ' + n + ' times']; // case 3: return ['yellow','Good job, keep up the good work! You\'ve practiced this sentence pair correctly ' + n + ' times']; // case 4: // default: return ['green','Excellent! Now you\'re fluent in this sentence pair — you did it right ' + n + ' times']; function convertToColour(p) { if (p > 0 && p < 25) return 'red'; else if (p >= 25 && p < 50) return 'orange'; else if (p >= 50 && p < 80) return 'yellow'; else if (p >= 80) return 'green'; return ''; } function getCompletePercentage(skillUrlName) { var skillInfo = arrayRequest(getCourseInfo('courseId'), skillUrlName), skillInfoLen = skillInfo.length, fullScore = 0, totalScore = 0, color = ''; for (var j = 0; j < skillInfoLen; j++) { var lessons = skillInfo[j][1], lessonsLen = lessons.length; for (var k = 0; k < lessonsLen; k++) { var sentences = lessons[k][1], sentencesLen = sentences.length; for (var l = 0; l < sentencesLen; l++) { fullScore += 1; totalScore += (sentences[l][2] > 0 ? 1 : 0); } } } return Math.floor(totalScore / (fullScore / 100)); } function getHTMLLayoutByRequest(scope, courseName, skillName, skillLevel, lessonNumber) { var layout = '', collectedlevels = [], len1 = duosentences.length; for (var course = 0; course < len1; course++) { var skills = duosentences[course]; if (scope >= 5) layout += '<div class="lang">'+skills[0]+'</div>'; if (courseName == undefined || courseName == skills[0]) { var len2 = skills[1].length; for (var skill = 0; skill < len2; skill++) { var levels = skills[1][skill]; if (scope >= 4) layout += '<div class="skill">' + levels[0]; if (skillName == undefined || skillName == levels[0]) { var len3 = levels[1].length; layout += '<div class="levelGroup grid' + len3 + '">'; for (var level = 0; level < len3; level++) { var lessons = levels[1][level], sentamount = 0, len4 = lessons[1].length; collectedlevels.push(lessons); for (var sent = 0; sent < len4; sent++) sentamount += lessons[1][sent][1].length; if (scope >= 3) layout += '<div class="level on level' + lessons[0] + '"><div class="tick"></div><span class="label">Level</span><span class="digit">' + lessons[0] + '</span><span class="sentencesCount"><b>' + sentamount + '</b> ' + (sentamount !== 1 ? 'sentences' : 'sentence') + '</span><button class="_3IjmU oNqWF _3hso2 _2vmUZ _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _2PUh7 H7AnT review-button" onclick="event.stopPropagation()">Review</button><div class="sentences-table requested hidden _3jZBz">'; if (skillLevel == undefined || skillLevel == lessons[0]) { for (var lesson = 0; lesson < len4; lesson++) { var sentences = lessons[1][lesson]; if (scope >= 2) layout += '<div class="lesson head">' + (sentences[0] == 'practice' ? 'Practice' : 'Lesson ' + sentences[0]) + '</div>'; if (lessonNumber == undefined || lessonNumber == sentences[0]) { var len5 = sentences[1].length; for (var sentence = 0; sentence < len5; sentence++) { var categories = sentences[1][sentence]; layout += '<div class="sentencePair"><div class="definition">'; function addSentBlock(n1,n2,classes,text) { var len6 = categories[n1][n2].length; for (var singlesentence = 0; singlesentence < len6; singlesentence++) { var info = getMarkInfo(categories[2]); layout += '<span class="sentence ' + classes + '"><span>' + categories[n1][n2][singlesentence].replace(' ?',' ?') + '</span></span>'; if (n1 == 1) layout += '<span class="practicesCounter" title="' + info[1] + '"><div class="indicator ' + info[0] + '"></div></span>'; // categories[2] return true; } return false; } if (!addSentBlock(0,0,'target duo','Target (given by Duo)')) addSentBlock(0,1,'target user','Target (given by user)'); layout += '</div><div class="definition">'; if (!addSentBlock(1,0,'native duo','Native (given by Duo)')) addSentBlock(1,1,'native user','Native (given by user)'); layout += '</div></div>'; } } } } layout += '</div></div>'; } layout += '</div>'; } } } } layout += '</div></div></div>'; layout += '<button class="TbLPl cVLwd _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _3Ry1f _2VaJD _23-CV _2arQ0 _2vmUZ _2Zh2S _1X3l0 eJd0I _3yrdh _2wXoR _1AM95 _1dlWz _2gnHr _1LsmY" id="startPracticeButton">Start practice</button>'; return [layout, collectedlevels]; } function getEntireTableHTMLLayout() { var layout = '<div id="table-wrap"><div id="showtable"></div><div class="sentences-table _3jZBz">', len1 = duosentences.length; for (var course = 0; course < len1; course++) { var skills = duosentences[course], len2 = skills[1].length; layout += '<div class="lang"><span class="head">' + skills[0].replace("DUOLINGO_","").replace("_",' <span style="color: #c1c1c1">(') + ")</span></span>"; for (var skill = 0; skill < len2; skill++) { var levels = skills[1][skill], len3 = levels[1].length; layout += '<div class="skill"><span class="head">' + levels[0].replace(/-/g, " ") +"</span>"; for (var level = 0; level < len3; level++) { var lessons = levels[1][level], len4 = lessons[1].length; layout += '<div class="level"><span class="head">Level ' + lessons[0]+"</span>"; for (var lesson = 0; lesson < len4; lesson++) { var sentences = lessons[1][lesson], len5 = sentences[1].length; layout += '<div class="lesson"><span class="head">' + (sentences[0] == 'practice' ? 'Practice' : 'Lesson ' + sentences[0])+"</span>"; for (var sentence = 0; sentence < len5; sentence++) { layout += '<div class="sentence"><div class="head">Sentence ' + (sentence + 1) + ': practiced <b>' + (sentences[1][sentence][2]) + '</b> time' + (sentences[1][sentence][2] !== 1 ? 's' : '') + '</div><div class="definition">'; function addSentBlock(n1,n2,classes,text) { var len6 = sentences[1][sentence][n1][n2].length; if (len6 > 0) layout += '<div class="cat ' + classes + '">' + text + '</div>'; for (var singlesentence = 0; singlesentence < len6; singlesentence++) { layout += '<span class="sentence ' + classes + '">' + sentences[1][sentence][n1][n2][singlesentence] + '</span>'; } } addSentBlock(0,0,'target duo','Target (Duo)'); addSentBlock(0,1,'target user','Target (User)'); layout += '</div><div class="definition">'; addSentBlock(1,0,'native duo','Native (Duo)'); addSentBlock(1,1,'native user','Native (User)'); layout += '</div></div>'; } layout += '</div>'; } layout += '</div>'; } layout += '</div>'; } layout += '</div>'; } layout += '</div></div>'; return layout; } // BUTTONS function startPractice(sentencesarray, skillName, amountofquestions) { var globalPractice = false, finished = false; if (skillName !== 'global') window.history.pushState("", "Translation Practice", "/skill/" + getCourseInfo('learningLanguage') + "/" + skillName.replace(/[\u0020]/g,'-') + "/translation-practice"); else { window.history.pushState("", "Translation Practice", "/global-practice"); globalPractice = true; } isPractice = true; includeInBody(practiceHTMLTemplate); var translationExercise = getById('translationExercise'); setTimeout(function(){ translationExercise.classList.add('shown'); },500); function activate(id) { if (!!(element = getById(id))) element.classList.add('active'); } function deactivateAndClick(id) { if (!!(element = getById(id))) { element.classList.remove('active'); element.click(); } } function bodykeydown(e) { switch (e.keyCode) { case 9: activate('skipSentence'); break; case 17: activate('iMistypedButton'); break; case 32: activate('iWasRightButton'); break; case 13: activate('continueButton'); break; } } function bodykeyup(e) { switch (e.keyCode) { case 27: if (confirm("Are you sure you want to quit? All progress in this session will be lost.")) endPractice(); break; case 9: deactivateAndClick('skipSentence'); break; case 17: deactivateAndClick('iMistypedButton'); break; case 32: deactivateAndClick('iWasRightButton'); break; case 13: deactivateAndClick('continueButton'); break; } } body.addEventListener("keydown", bodykeydown); body.addEventListener("keyup", bodykeyup); function endPractice() { body.removeEventListener("keydown", bodykeydown); body.removeEventListener("keyup", bodykeyup); if (finished) translationExercise.classList.add('phrase' + getRandomInt(1,13), 'finish'); setTimeout(function(){ if (substituted == false) { translationExercise.classList.remove('shown'); document.getElementsByTagName('html')[0].classList.remove("sentenceTraining"); setTimeout(function(){ removeElement(translationExercise); },350); window.history.pushState("", "Duolingo", "/learn"); if (!!thisSentencesButton) { var completePercentage = getCompletePercentage(thisSentencesButton.getAttribute('data-sentences-skill-name')); thisSentencesButton.title = 'Proficiency: ' + completePercentage + '%'; thisSentencesButton.classList.add(convertToColour(completePercentage)); } } else location.assign("/learn"); isPractice = false; }, finished ? 2500 : 0); } getById('endPractice').addEventListener('click', endPractice); var sentencePairsArray = generateQuestions(sentencesarray, amountofquestions), curSentence = 1, learningLanguage = getCourseInfo('learningLanguage'), fromLanguage = getCourseInfo('fromLanguage'), learningLanguageName = getCourseInfo('learningLanguageName'), streak = 0, streakBackup = 0; function updateControlsArea(template) { getById('controlsArea').innerHTML = template; } function outputIntro(){ updateControlsArea(practiceStartTemplate); getById('moduleContainer').innerHTML = globalPractice ? globalWelcomeTemplate : welcomeTemplate; getById('continueButton').addEventListener('click',function(){ getById('moduleContainer').innerHTML = '<div class="_3IpBw"></div>'; getById('headerContainer').innerHTML = practiceHeadTemplate; getById('TTSswitch').classList.add(ttsEnabled ? 'on' : 'off'); getById('TTSswitch').addEventListener('click', function(){ function toggle(cl1, cl2, newval, elem) { elem.classList.replace(cl1, cl2); ttsEnabled = newval; setStorageItm('ttsEnabled', JSON.stringify(newval)); } if (this.classList.contains('on')) toggle('on','off', false, this); else toggle('off','on', true, this); if (!!(targetInput = getById('targetInput'))) targetInput.focus(); }); outputQuestion(); getById('endPractice').addEventListener('click', endPractice); }); } outputIntro(); function outputQuestion() { updateControlsArea(practiceCheckTemplate); var existingChallenge = getById('challenge'); if (!!existingChallenge) { existingChallenge.classList.remove('tZPfh'); existingChallenge.classList.add('_1Fe6z','_1sR1V','_1sKP2'); setTimeout(function(){ removeElement(existingChallenge); },450); } firstOfSelector('#moduleContainer ._3IpBw').insertAdjacentHTML('afterbegin',challengeTemplate); if (keyboardDefined && getStorageItm('keyboard') !== '' && getCourseInfo('courseId') == getStorageItm('keyboardLocale')) { var targetInput = getById('targetInput'); targetInput.insertAdjacentHTML('afterend', '<div class="I1fg4 _1lVk6">' + getStorageItm('keyboard') + '</div>'); var keybuttons = targetInput.parentNode.querySelectorAll('._1tSEs'), keybuttonslength = keybuttons.length; function lowerCase() { keybuttons[0].innerText = '↑'; for (var i = 1; i < keybuttonslength; i++) { keybuttons[i].innerText = keybuttons[i].innerText.toLowerCase(); } } function upperCase() { keybuttons[0].innerText = '↓'; for (var i = 1; i < keybuttonslength; i++) { keybuttons[i].innerText = keybuttons[i].innerText.toUpperCase(); } } if (keybuttons[0].innerText == '↓') lowerCase(); for (var i = 0; i < keybuttonslength; i++) keybuttons[i].disabled = false; keybuttons[0].onclick = function(){ if (this.innerText == '↓') lowerCase(); else upperCase(); } for (var i = 1; i < keybuttonslength; i++) { keybuttons[i].onclick = function(){ var toInsert = this.innerText; if (document.selection) { targetInput.focus(); var sel = document.selection.createRange(); sel.text = toInsert; } else if (targetInput.selectionStart || targetInput.selectionStart == '0') { var startPos = targetInput.selectionStart; var endPos = targetInput.selectionEnd; targetInput.value = targetInput.value.substring(0, startPos) + toInsert + targetInput.value.substring(endPos, targetInput.value.length); targetInput.selectionStart = startPos + toInsert.length; targetInput.selectionEnd = startPos + toInsert.length; } else targetInput.value += toInsert; targetInput.focus(); } } } var curSentencePair = sentencePairsArray[curSentence - 1], targetSentence = curSentencePair[0], nativeSentence = curSentencePair[1], targetInput = getById('targetInput'), continueButton = getById('continueButton'); targetInput.setAttribute('placeholder','Type in ' + learningLanguageName); getById('writeThis').innerText = 'Write this in ' + learningLanguageName; //RESET targetInput.disabled = false; targetInput.value = ''; targetInput.focus(); getById('nativeSentence').innerHTML = nativeSentence; // playTTS(fromLanguage,nativeSentence); targetInput.addEventListener("keyup", function(e) { if (targetInput.value !== '') { continueButton.disabled = false; continueButton.classList.add('_2VaJD','_23-CV'); } else { continueButton.disabled = true; continueButton.classList.remove('_2VaJD','_23-CV'); } }); targetInput.addEventListener("keydown", function(e) { if (e.keyCode === 13) { e.preventDefault(); } }); continueButton.onclick = function(){ if (targetInput.value !== '') validate(targetInput.value); }; getById('skipSentence').onclick = function(){ validate(''); }; function updateProgressBar() { getById('progressBar').style = "opacity: 1; width: " + (100 / sentencePairsArray.length) * curSentence + "%;"; } function validate(string) { targetInput.disabled = true; var nativeKeyboardButtons = targetInput.parentNode.querySelectorAll('._1tSEs'), buttonsLength = nativeKeyboardButtons.length; for (var i = 0; i < buttonsLength; i++) { nativeKeyboardButtons[i].disabled = true; } var correct = false; function update(template) { updateControlsArea(template); continueButton = getById('continueButton'); continueButton.onclick = function(){ if (curSentence !== sentencePairsArray.length) { curSentence++; outputQuestion(); getById('progressBar').querySelectorAll('.JotLT').forEach(function(label){ removeElement(label); }); } else { var sound = getById('lessonCompleted'); sound.volume = 0.5; sound.play(); finished = true; endPractice(); } } } function result(template, outputText, outputID) { update(template); var sound = getById(correct ? 'successSound' : 'wrongSound'); sound.volume = 0.3; sound.play(); if (ttsEnabled) playTTS(learningLanguage,outputText); if (correct) { streak++; var equalizedOutput = equalizeString(outputText, true), equalizedString = equalizeString(string, true); function recreateOriginalArray(toRecreate, reconstructionArray) { var reconstructionArrayLen = reconstructionArray.length; for (var elem = 0; elem <= reconstructionArrayLen - 1; elem++) { toRecreate = toRecreate.slice(0, reconstructionArray[elem][1]) .concat(makeSeparate(reconstructionArray[elem][0].split(''))) .concat(toRecreate.slice(reconstructionArray[elem][1] + reconstructionArray[elem][2])); } return toRecreate; } if (equalizedOutput[0].toLowerCase() !== equalizedString[0].toLowerCase()) { var charArr = [], layout = '', equalizedOutputLen = equalizedOutput[0].length; for (var char = 0; char < equalizedOutputLen; char++) { var outputChar = equalizedOutput[0].charAt(char); if (equalizedString[0].charAt(char).toLowerCase() !== outputChar.toLowerCase()) charArr.push([outputChar,'underlined']); else charArr.push([outputChar]); } var arr = recreateOriginalArray(charArr,equalizedOutput[1]), arrlen = arr.length; for (var char = 0; char < arrlen; char++) layout += !!arr[char][1] ? '<u>' + arr[char][0] + '</u>' : arr[char][0]; getById('youAreCorrect').innerHTML = 'Pay attention to the accents<div class="_75iiA"><span><span id="withFormatting">' + layout.replace(/( \?)+/g, " ?").replace(/( \!)+/g, " !") + '</span></span></div>'; } } else { streakBackup = streak; streak = 0; getById(outputID).innerHTML = outputText.replace(/( \?)+/g, " ?").replace(/( \!)+/g, " !"); } setStreak(streak, curSentence, sentencePairsArray.length); } function increasePracticedCounter() { arrayRequest(getCourseInfo('courseId'), curSentencePair[3], curSentencePair[4], curSentencePair[5], curSentencePair[6]); } var targetCategories = curSentencePair[2], foundInDuo = equalizeArray(targetCategories[0]).indexOf(equalizeString(string, false)), foundInUser = equalizeArray(targetCategories[1]).indexOf(equalizeString(string, false)); if (foundInDuo !== -1 || foundInUser !== -1) { correct = true; if (foundInDuo !== -1) result(practiceCorrectTemplate, targetCategories[0][foundInDuo], 'withFormatting'); else result(practiceCorrectTemplate, targetCategories[1][foundInUser], 'withFormatting'); if (curSentence <= amountofquestions) increasePracticedCounter(); } else { sentencePairsArray.push(curSentencePair); result(practiceWrongTemplate, targetSentence, 'correctSolution'); } updateProgressBar(); if (!correct) { if (string !== '') { function makeCorrect() { increasePracticedCounter(); streak = streakBackup + 1; sentencePairsArray = sentencePairsArray.slice(0, sentencePairsArray.length - 1); setStreak(streak, curSentence, sentencePairsArray.length); updateProgressBar(); continueButton.click(); } getById('iWasRightButton').onclick = function() { this.disabled = true; addSentences(getCourseInfo('courseId'), curSentencePair[3], curSentencePair[4], curSentencePair[5], inheritFormatting(getById('correctSolution').innerText, targetInput.value), nativeSentence, false, false); makeCorrect(); } getById('iMistypedButton').onclick = function() { this.disabled = true; makeCorrect(); } } else removeElement(firstOfSelector('.buttonGroup')); } } } if (substituted) window.stop(); } function createTrainingDialog(skillName){ includeInBody('<div class="BKNBq _1CJpK _1AbdB dialog-wrap" id="sentences-dialog-wrap"><div id="sentences-dialog" class="_1bYPb _3gvMn _3I5-U _2CNG0 _2-QsC dialog" tabindex="-1" role="dialog" onclick="event.stopPropagation()"><div class="_1ePWu" id="sentences-dialog-close"><img src="https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877714/x_sq1jmd.svg"></div><div class="_1ixZq"><h1 class="_3oZIl">' + skillName.replace(/[\-]/g,' ') + '</h1></div></div></div>'); var dialogWrap = getById('sentences-dialog-wrap'); function closeDialog() { dialogWrap.classList.add('hidden'); setTimeout(function(){ removeElement(dialogWrap); }, 500); } getById('sentences-dialog-close').addEventListener('click',closeDialog); dialogWrap.addEventListener('click',closeDialog); var HTMLArray = getHTMLLayoutByRequest(3, getCourseInfo('courseId'), skillName); dialogWrap.querySelectorAll('._1ixZq')[0].insertAdjacentHTML('beforeend', HTMLArray[0]); var startbutton = getById('startPracticeButton'); var levelButtons = allOfSelector('.level'); for (var i = 0; i < levelButtons.length; i++) { levelButtons[i].onclick = function(){ if (this.classList.contains('on')) { this.classList.replace('on','off'); if (allOfSelector('.level.on').length == 0) startbutton.disabled = true; } else { this.classList.replace('off','on'); startbutton.disabled = false; } } } var reviewButtons = allOfSelector('.review-button'); for (var i = 0; i < reviewButtons.length; i++) { reviewButtons[i].onclick = function(event){ event.stopPropagation(); reviewSentences(skillName.replace(/[\-]/g,' '), this.parentNode.querySelectorAll('.sentences-table')[0]); }; } startbutton.onclick = function(){ dialogWrap.classList.add('hidden'); setTimeout(function(){ removeElement(dialogWrap); document.getElementsByTagName('html')[0].classList.add('sentenceTraining'); }, 1000); var levelButtons = allOfSelector('#sentences-dialog-wrap .level'), filteredHTMLArray = []; for (var i = 0; i < levelButtons.length; i++) { if (levelButtons[i].classList.contains('on')) filteredHTMLArray.push(HTMLArray[1][i]); } startPractice([[skillName, filteredHTMLArray]], skillName, 20); }; } function reviewSentences(skillName, table) { includeInBody('<div class="BKNBq _1CJpK _1AbdB dialog-wrap" id="review-sentences-dialog-wrap"><div id="review-sentences-dialog" class="_1bYPb _3gvMn _3I5-U _2CNG0 _2-QsC dialog" tabindex="-1" role="dialog" onclick="event.stopPropagation()"><div class="_1ePWu" id="review-sentences-dialog-close"><img src="https://res.cloudinary.com/dn6n8yqqh/image/upload/v1562877714/x_sq1jmd.svg"></div><div class="_1ixZq"><h1 class="_3oZIl">' + skillName + ': sentences</h1></div></div></div>'); var dialogWrap = getById('review-sentences-dialog-wrap'); function closeDialog() { dialogWrap.classList.add('hidden'); setTimeout(function(){ removeElement(dialogWrap); }, 500); } getById('review-sentences-dialog-close').addEventListener('click',closeDialog); dialogWrap.addEventListener('click',closeDialog); dialogWrap.querySelectorAll('._1ixZq')[0].insertAdjacentElement('beforeend', table.cloneNode(true)); } // FETCH SENTENCES function fetchSentencesFromExercise(taskType) { function getSentenceFromHintToken() { var elements = allOfSelector('[data-test="hint-token"]'), elementsLen = elements.length, sentence = ""; for (var i = 0; i < elementsLen; i++) { var childNodesLen = elements[i].childNodes.length; for (var j = 0; j < childNodesLen; j++) { if (elements[i].childNodes[j].nodeName == "#text") sentence += elements[i].childNodes[j].nodeValue; } } return sentence; } switch (taskType) { case 'challenge-listen': case 'challenge-listenTap': var TL, NL, TLDuo = false; TL = firstOfSelector('[data-test*="challenge-translate-input"]').value; NL = firstOfSelector('._2GiCe').innerText.replace('Meaning: ',''); var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; if (newTL.innerText == 'They will be back in 1 hour.') return null; } else TL = inheritFormatting(NL, TL); return [TL,NL,TLDuo,true]; break; case 'challenge-translate': var soundButton = allOfSelector('._2ESN4'), TL, NL, TLDuo = true, NLDuo = true, another = undefined; if (!!soundButton[0]) { TL = getSentenceFromHintToken(); NL = allOfSelector('[data-test*="challenge-translate-input"]'); NL = inheritFormatting(TL, NL[NL.length - 1].value); var newNL = firstOfSelector('._75iiA'); if (!!newNL) { if (!!firstOfSelector('._3H0e2._28jVs') && firstOfSelector('._3H0e2._28jVs').childNodes[0].nodeValue == 'Another correct solution:') another = NL; NL = newNL.innerText; NLDuo = true; } return [TL,NL,TLDuo,NLDuo,another,'NL']; } else { NL = getSentenceFromHintToken(); TL = inheritFormatting(NL, !!firstOfSelector('[data-test*="challenge-translate-input"]') ? firstOfSelector('[data-test*="challenge-translate-input"]').value : firstOfSelector("._3Ptco").innerText.replace(/[\t\n\r]/g,' ')); TLDuo = false; var newTL = firstOfSelector('._75iiA'); if (!!newTL) { if (!!firstOfSelector('._3H0e2._28jVs') && firstOfSelector('._3H0e2._28jVs').childNodes[0].nodeValue == 'Another correct solution:') another = TL; TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo,another,'TL']; } break; case 'challenge-speak': var TL = "", NL; TL = firstOfSelector('._3_NyK._1Juqt').textContent; NL = firstOfSelector('._2GiCe').innerText.replace('Meaning: ',''); return [TL,NL,true,true]; break; case 'challenge-completeReverseTranslation': var TL, NL, TLDuo = false, NLDuo = true; NL = getSentenceFromHintToken(); TL = inheritFormatting(NL, firstOfSelector('._3_NyK._1Juqt').textContent.replace(/[_]/g,'')); var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo]; break; case 'challenge-tapDescribe': var TL, NL, TLDuo = true, NLDuo = true; TL = firstOfSelector("._3Ptco").innerText.replace(/[\t\n\r]/g,' '); NL = firstOfSelector('._2GiCe').innerText.replace('Meaning: ',''); var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo]; break; case 'challenge-form': var TL, NL, TLDuo = true, NLDuo = true; TL = firstOfSelector('[data-test="challenge-form-prompt"]').getAttribute("data-prompt").replace(/_+/g, firstOfSelector('._3DsW- ._2gaCX').innerText.replace(/[\t\n\r]/g,' ')); NL = firstOfSelector('._2GiCe').innerText.replace('Meaning: ',''); var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo]; break; case 'challenge-tapComplete': var TL, NL, TLDuo = true, NLDuo = true; TL = firstOfSelector('._2R9tm').innerText.replace(/[\t\n\r]/g,''); NL = firstOfSelector('._2GiCe').innerText.replace('Meaning: ',''); var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo]; break; case 'challenge-judge': var TL, NL, TLDuo = true, NLDuo = true; TL = firstOfSelector('._2QNyK._3DsW- .loqxs').innerText; NL = firstOfSelector('.KRKEd').innerText; var newTL = firstOfSelector('._75iiA'); if (!!newTL) { TL = newTL.innerText; TLDuo = true; } return [TL,NL,TLDuo,NLDuo]; break; } } // MONITORING THE SCREEN var isFound = false, treeUpdated = false, sideBarModuleAdded = false; updateTable(); function reset(){ treeUpdated = false; sideBarModuleAdded = false; } // document.addEventListener("DOMContentLoaded", function(){ // body.addEventListener("keyup", function(e){ // if (e.altKey && e.which == 69) { // var showtable = getById('showtable'); // if (showtable.style.opacity == '' || showtable.style.opacity == '0') { // showtable.style.opacity = '1'; // showtable.style.display = 'block'; // } // else { // showtable.style.opacity = '0'; // setTimeout(function(){ showtable.style.display = 'none'; }, 200); // } // } // }); // }); window.onload = function(){ setInterval(function(){ if (/\.com\/$/g.test(window.location.href) || /\.com\/learn$/g.test(window.location.href)) { if (!!firstOfSelector('[data-test="skill-tree"]')) { if (getCourseInfo('courseId') !== getStorageItm('updatedTree')) { reset(); setStorageItm('updatedTree', getCourseInfo('courseId')); updateParsedDuoState(); } if (!treeUpdated) { treeUpdated = true; sideBarModuleAdded = false; updateParsedDuoState(); skillsArray = getSkillsForCurrentLanguage(); var skillsCollection = allOfSelector('._33VdW:not(.AlP1u):not(._1Zjfp)'), skillsCollectionLen = skillsCollection.length, currentLanguageSkillsCollection = [], namesCollection = []; if (!!(request = arrayRequest(getCourseInfo('courseId')))) { currentLanguageSkillsCollection = getNames(request); for (var i = 0; i < skillsCollectionLen; i++) { var skill = skillsCollection[i], indexInNamesCollection = namesCollection.indexOf(skill.innerText); if (indexInNamesCollection == -1) { namesCollection.push(skill.innerText); namesCollection.push(0); } else namesCollection[indexInNamesCollection + 1]++; var skillUrlName = getURLNameByShortName(skill.innerText, namesCollection[namesCollection.indexOf(skill.innerText) + 1]); if (currentLanguageSkillsCollection.includes(skillUrlName)) { var completePercentage = getCompletePercentage(skillUrlName); skill.parentNode.parentNode.insertAdjacentHTML('afterbegin','<div class="sentences-button ' + convertToColour(completePercentage) + '" onclick="event.stopPropagation()" title="Proficiency: ' + completePercentage + '%" data-sentences-skill-name="' + skillUrlName + '"></div>'); skill.setAttribute('data-skill-url-name', skillUrlName); } else { skill.parentNode.parentNode.parentNode.classList.add('no-sentences'); skill.setAttribute('data-skill-url-name', 'no-sentences'); } } allOfSelector('.sentences-button').forEach(function(button){ button.onclick = function(event){ event.stopPropagation(); thisSentencesButton = this; createTrainingDialog(this.getAttribute('data-sentences-skill-name')); }; }); } } if (!sideBarModuleAdded) { sideBarModuleAdded = true; if (arrayRequest(getCourseInfo('courseId'))) { removePracticeModule(false); createGlobalPracticeButton(); } else removePracticeModule(true); } } else reset(); } else { if (treeUpdated && !isPractice) { window.removeEventListener('scroll', updateTransform); removePracticeModule(true); reset(); } if (!!firstOfSelector('h2._28jVs') && !firstOfSelector('html').classList.contains('sentenceTraining') && !['translation-practice','test'].includes(getLessonIndex())) { if (!isFound) { isFound = true; var challengeType = firstOfSelector('[data-test^="challenge "]').getAttribute('data-test').split(" ")[1]; if (['challenge-listen', 'challenge-listenTap', 'challenge-translate', 'challenge-speak', 'challenge-completeReverseTranslation', 'challenge-tapDescribe', 'challenge-form', 'challenge-tapComplete', 'challenge-judge'].includes(challengeType)) { var sentences = fetchSentencesFromExercise(challengeType), courseId = getCourseInfo('courseId'), skillName = getSkillName(), lessonIndex = getLessonIndex(), levelOfSkill = getLevelOfSkill(skillName); console.log("Target: " + sentences[0]); console.log("Native: " + sentences[1]); if (sentences !== null && skillName !== null && lessonIndex !== null && levelOfSkill !== null) { addSentences(courseId, skillName, levelOfSkill, lessonIndex, sentences[0], sentences[1], sentences[2], sentences[3]); if (sentences[4] !== undefined) { if (sentences[5] == 'NL') addSentences(courseId, skillName, levelOfSkill, lessonIndex, sentences[0], sentences[4], sentences[2], false); else addSentences(courseId, skillName, levelOfSkill, lessonIndex, sentences[4], sentences[1], false, sentences[3]); console.log('Another correct solution: ' + sentences[4]); } } console.log("Skill name: " + skillName); console.log("Skill level: " + levelOfSkill); console.log("Lesson index: " + lessonIndex); console.log("————————————————————————————————————————"); } } } else isFound = false; if (!!firstOfSelector('textarea[autocorrect][spellcheck]') && getLessonIndex() !== 'translation-practice') { var keyboard = firstOfSelector('textarea[autocorrect][spellcheck] + .I1fg4'); if (!!keyboard) { if ((!keyboardDefined || keyboard.innerHTML !== getStorageItm('keyboard')) && getCourseInfo('courseId') !== getStorageItm('keyboardLocale')){ setStorageItm('keyboard',keyboard.innerHTML); setStorageItm('keyboardLocale',getCourseInfo('courseId')); keyboardDefined = true; } } else setStorageItm('keyboard', ''); } } },300); };