Merge pull request #3593 from BookStackApp/code-editor-favorites
Code-editor lang favorites system
This commit is contained in:
		
						commit
						050ae01f94
					
				| 
						 | 
					@ -289,6 +289,27 @@ class UserController extends Controller
 | 
				
			||||||
        return response('', 204);
 | 
					        return response('', 204);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function updateCodeLanguageFavourite(Request $request)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $validated = $this->validate($request, [
 | 
				
			||||||
 | 
					            'language' => ['required', 'string', 'max:20'],
 | 
				
			||||||
 | 
					            'active' => ['required', 'bool'],
 | 
				
			||||||
 | 
					        ]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $currentFavoritesStr = setting()->getForCurrentUser('code-language-favourites', '');
 | 
				
			||||||
 | 
					        $currentFavorites = array_filter(explode(',', $currentFavoritesStr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $isFav = in_array($validated['language'], $currentFavorites);
 | 
				
			||||||
 | 
					        if (!$isFav && $validated['active']) {
 | 
				
			||||||
 | 
					            $currentFavorites[] = $validated['language'];
 | 
				
			||||||
 | 
					        } else if ($isFav && !$validated['active']) {
 | 
				
			||||||
 | 
					            $index = array_search($validated['language'], $currentFavorites);
 | 
				
			||||||
 | 
					            array_splice($currentFavorites, $index, 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        setting()->putUser(user(), 'code-language-favourites', implode(',', $currentFavorites));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Changed the stored preference for a list sort order.
 | 
					     * Changed the stored preference for a list sort order.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,7 @@ import 'codemirror/addon/scroll/scrollpastend';
 | 
				
			||||||
// Value can be a mode string or a function that will receive the code content & return the mode string.
 | 
					// Value can be a mode string or a function that will receive the code content & return the mode string.
 | 
				
			||||||
// The function option is used in the event the exact mode could be dynamic depending on the code.
 | 
					// The function option is used in the event the exact mode could be dynamic depending on the code.
 | 
				
			||||||
const modeMap = {
 | 
					const modeMap = {
 | 
				
			||||||
 | 
					    bash: 'shell',
 | 
				
			||||||
    css: 'css',
 | 
					    css: 'css',
 | 
				
			||||||
    c: 'text/x-csrc',
 | 
					    c: 'text/x-csrc',
 | 
				
			||||||
    java: 'text/x-java',
 | 
					    java: 'text/x-java',
 | 
				
			||||||
| 
						 | 
					@ -88,7 +89,6 @@ const modeMap = {
 | 
				
			||||||
    shell: 'shell',
 | 
					    shell: 'shell',
 | 
				
			||||||
    sh: 'shell',
 | 
					    sh: 'shell',
 | 
				
			||||||
    stext: 'text/x-stex',
 | 
					    stext: 'text/x-stex',
 | 
				
			||||||
    bash: 'shell',
 | 
					 | 
				
			||||||
    toml: 'toml',
 | 
					    toml: 'toml',
 | 
				
			||||||
    ts: 'text/typescript',
 | 
					    ts: 'text/typescript',
 | 
				
			||||||
    typescript: 'text/typescript',
 | 
					    typescript: 'text/typescript',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,17 +10,20 @@ class CodeEditor {
 | 
				
			||||||
        this.container = this.$refs.container;
 | 
					        this.container = this.$refs.container;
 | 
				
			||||||
        this.popup = this.$el;
 | 
					        this.popup = this.$el;
 | 
				
			||||||
        this.editorInput = this.$refs.editor;
 | 
					        this.editorInput = this.$refs.editor;
 | 
				
			||||||
        this.languageLinks = this.$manyRefs.languageLink;
 | 
					        this.languageButtons = this.$manyRefs.languageButton;
 | 
				
			||||||
 | 
					        this.languageOptionsContainer = this.$refs.languageOptionsContainer;
 | 
				
			||||||
        this.saveButton = this.$refs.saveButton;
 | 
					        this.saveButton = this.$refs.saveButton;
 | 
				
			||||||
        this.languageInput = this.$refs.languageInput;
 | 
					        this.languageInput = this.$refs.languageInput;
 | 
				
			||||||
        this.historyDropDown = this.$refs.historyDropDown;
 | 
					        this.historyDropDown = this.$refs.historyDropDown;
 | 
				
			||||||
        this.historyList = this.$refs.historyList;
 | 
					        this.historyList = this.$refs.historyList;
 | 
				
			||||||
 | 
					        this.favourites = new Set(this.$opts.favourites.split(','));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.callback = null;
 | 
					        this.callback = null;
 | 
				
			||||||
        this.editor = null;
 | 
					        this.editor = null;
 | 
				
			||||||
        this.history = {};
 | 
					        this.history = {};
 | 
				
			||||||
        this.historyKey = 'code_history';
 | 
					        this.historyKey = 'code_history';
 | 
				
			||||||
        this.setupListeners();
 | 
					        this.setupListeners();
 | 
				
			||||||
 | 
					        this.setupFavourites();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    setupListeners() {
 | 
					    setupListeners() {
 | 
				
			||||||
| 
						 | 
					@ -30,7 +33,7 @@ class CodeEditor {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        onSelect(this.languageLinks, event => {
 | 
					        onSelect(this.languageButtons, event => {
 | 
				
			||||||
            const language = event.target.dataset.lang;
 | 
					            const language = event.target.dataset.lang;
 | 
				
			||||||
            this.languageInput.value = language;
 | 
					            this.languageInput.value = language;
 | 
				
			||||||
            this.languageInputChange(language);
 | 
					            this.languageInputChange(language);
 | 
				
			||||||
| 
						 | 
					@ -49,6 +52,58 @@ class CodeEditor {
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    setupFavourites() {
 | 
				
			||||||
 | 
					        for (const button of this.languageButtons) {
 | 
				
			||||||
 | 
					            this.setupFavouritesForButton(button);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.sortLanguageList();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * @param {HTMLButtonElement} button
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    setupFavouritesForButton(button) {
 | 
				
			||||||
 | 
					        const language = button.dataset.lang;
 | 
				
			||||||
 | 
					        let isFavorite = this.favourites.has(language);
 | 
				
			||||||
 | 
					        button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        onChildEvent(button.parentElement, '.lang-option-favorite-toggle', 'click', () => {
 | 
				
			||||||
 | 
					            isFavorite = !isFavorite;
 | 
				
			||||||
 | 
					            isFavorite ? this.favourites.add(language) : this.favourites.delete(language);
 | 
				
			||||||
 | 
					            button.setAttribute('data-favourite', isFavorite ? 'true' : 'false');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            window.$http.patch('/settings/users/update-code-language-favourite', {
 | 
				
			||||||
 | 
					                language: language,
 | 
				
			||||||
 | 
					                active: isFavorite
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.sortLanguageList();
 | 
				
			||||||
 | 
					            if (isFavorite) {
 | 
				
			||||||
 | 
					                button.scrollIntoView({block: "center", behavior: "smooth"});
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sortLanguageList() {
 | 
				
			||||||
 | 
					        const sortedParents = this.languageButtons.sort((a, b) => {
 | 
				
			||||||
 | 
					            const aFav = a.dataset.favourite === 'true';
 | 
				
			||||||
 | 
					            const bFav = b.dataset.favourite === 'true';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (aFav && !bFav) {
 | 
				
			||||||
 | 
					                return -1;
 | 
				
			||||||
 | 
					            } else if (bFav && !aFav) {
 | 
				
			||||||
 | 
					                return 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return a.dataset.lang > b.dataset.lang ? 1 : -1;
 | 
				
			||||||
 | 
					        }).map(button => button.parentElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (const parent of sortedParents) {
 | 
				
			||||||
 | 
					            this.languageOptionsContainer.append(parent);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    save() {
 | 
					    save() {
 | 
				
			||||||
        if (this.callback) {
 | 
					        if (this.callback) {
 | 
				
			||||||
            this.callback(this.editor.getValue(), this.languageInput.value);
 | 
					            this.callback(this.editor.getValue(), this.languageInput.value);
 | 
				
			||||||
| 
						 | 
					@ -94,15 +149,13 @@ class CodeEditor {
 | 
				
			||||||
    languageInputChange(language) {
 | 
					    languageInputChange(language) {
 | 
				
			||||||
        this.updateEditorMode(language);
 | 
					        this.updateEditorMode(language);
 | 
				
			||||||
        const inputLang = language.toLowerCase();
 | 
					        const inputLang = language.toLowerCase();
 | 
				
			||||||
        let matched = false;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for (const link of this.languageLinks) {
 | 
					        for (const link of this.languageButtons) {
 | 
				
			||||||
            const lang = link.dataset.lang.toLowerCase().trim();
 | 
					            const lang = link.dataset.lang.toLowerCase().trim();
 | 
				
			||||||
            const isMatch = inputLang && lang.startsWith(inputLang);
 | 
					            const isMatch = inputLang === lang;
 | 
				
			||||||
            link.classList.toggle('active', isMatch);
 | 
					            link.classList.toggle('active', isMatch);
 | 
				
			||||||
            if (isMatch && !matched) {
 | 
					            if (isMatch) {
 | 
				
			||||||
                link.scrollIntoView({block: "center", behavior: "smooth"});
 | 
					                link.scrollIntoView({block: "center", behavior: "smooth"});
 | 
				
			||||||
                matched = true;
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -666,17 +666,48 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
				
			||||||
  text-align: left;
 | 
					  text-align: left;
 | 
				
			||||||
  font-family: $mono;
 | 
					  font-family: $mono;
 | 
				
			||||||
  font-size: 0.7rem;
 | 
					  font-size: 0.7rem;
 | 
				
			||||||
 | 
					  padding-left: 24px + $-xs;
 | 
				
			||||||
  &:hover, &.active {
 | 
					  &:hover, &.active {
 | 
				
			||||||
    background-color: var(--color-primary-light);
 | 
					    background-color: var(--color-primary-light);
 | 
				
			||||||
    color: var(--color-primary);
 | 
					    color: var(--color-primary);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.code-editor button.lang-option-favorite-toggle {
 | 
				
			||||||
 | 
					  position: absolute;
 | 
				
			||||||
 | 
					  top: 0;
 | 
				
			||||||
 | 
					  left: 0;
 | 
				
			||||||
 | 
					  width: 28px;
 | 
				
			||||||
 | 
					  font-size: 1rem;
 | 
				
			||||||
 | 
					  border: 0;
 | 
				
			||||||
 | 
					  line-height: 1;
 | 
				
			||||||
 | 
					  padding: 2px;
 | 
				
			||||||
 | 
					  z-index: 2;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  color: var(--color-primary);
 | 
				
			||||||
 | 
					  svg {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.code-editor button[data-favourite="true"] ~ .action-favourite,
 | 
				
			||||||
 | 
					.code-editor button[data-favourite="false"] ~ .action-unfavourite {
 | 
				
			||||||
 | 
					  display: none;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.code-editor .action-favourite {
 | 
				
			||||||
 | 
					  opacity: 0.5;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					.code-editor button:hover ~ .action-favourite {
 | 
				
			||||||
 | 
					  opacity: 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.code-editor label {
 | 
					.code-editor label {
 | 
				
			||||||
  background-color: var(--color-primary-light);
 | 
					  background-color: var(--color-primary-light);
 | 
				
			||||||
  width: 100%;
 | 
					  width: 100%;
 | 
				
			||||||
  color: var(--color-primary);
 | 
					  color: var(--color-primary);
 | 
				
			||||||
  padding: $-xxs $-m;
 | 
					  padding: $-xxs $-s;
 | 
				
			||||||
  margin-bottom: 0;
 | 
					  margin-bottom: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -691,7 +722,8 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
				
			||||||
  border-radius: 0;
 | 
					  border-radius: 0;
 | 
				
			||||||
  border: 0;
 | 
					  border: 0;
 | 
				
			||||||
  border-bottom: 1px solid #DDD;
 | 
					  border-bottom: 1px solid #DDD;
 | 
				
			||||||
  padding: $-xs $-m;
 | 
					  padding: $-xs $-s;
 | 
				
			||||||
 | 
					  height: auto;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.code-editor-main {
 | 
					.code-editor-main {
 | 
				
			||||||
| 
						 | 
					@ -705,6 +737,10 @@ body.flexbox-support #entity-selector-wrap .popup-body .form-group {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.code-editor-body-wrap {
 | 
				
			||||||
 | 
					  height: 80vh;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@include smaller-than($s) {
 | 
					@include smaller-than($s) {
 | 
				
			||||||
  .code-editor .lang-options {
 | 
					  .code-editor .lang-options {
 | 
				
			||||||
    display: none;
 | 
					    display: none;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,7 @@
 | 
				
			||||||
<div>
 | 
					<div>
 | 
				
			||||||
    <div components="popup code-editor" class="popup-background code-editor">
 | 
					    <div components="popup code-editor"
 | 
				
			||||||
 | 
					         option:code-editor:favourites="{{ setting()->getForCurrentUser('code-language-favourites', '') }}"
 | 
				
			||||||
 | 
					         class="popup-background code-editor">
 | 
				
			||||||
        <div refs="code-editor@container" class="popup-body" tabindex="-1">
 | 
					        <div refs="code-editor@container" class="popup-body" tabindex="-1">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <div class="popup-header flex-container-row primary-background">
 | 
					            <div class="popup-header flex-container-row primary-background">
 | 
				
			||||||
| 
						 | 
					@ -18,42 +20,23 @@
 | 
				
			||||||
                <div class="code-editor-language-list flex-container-column flex-fill">
 | 
					                <div class="code-editor-language-list flex-container-column flex-fill">
 | 
				
			||||||
                    <label for="code-editor-language">{{ trans('components.code_language') }}</label>
 | 
					                    <label for="code-editor-language">{{ trans('components.code_language') }}</label>
 | 
				
			||||||
                    <input refs="code-editor@languageInput" id="code-editor-language" type="text">
 | 
					                    <input refs="code-editor@languageInput" id="code-editor-language" type="text">
 | 
				
			||||||
                    <div class="lang-options">
 | 
					                    <div refs="code-editor@language-options-container" class="lang-options">
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="CSS">CSS</button>
 | 
					                        @php
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="C">C</button>
 | 
					                            $languages = [
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="C++">C++</button>
 | 
					                                'Bash', 'CSS', 'C', 'C++', 'C#', 'Diff', 'Fortran', 'F#', 'Go', 'Haskell', 'HTML', 'INI',
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="C#">C#</button>
 | 
					                                'Java', 'JavaScript', 'JSON', 'Julia', 'Kotlin', 'LaTeX', 'Lua', 'MarkDown', 'Nginx', 'OCaml',
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="diff">Diff</button>
 | 
					                                'Pascal', 'Perl', 'PHP', 'Powershell', 'Python', 'Ruby', 'Rust', 'Shell', 'SQL', 'TypeScript',
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Fortran">Fortran</button>
 | 
					                                'VBScript', 'VB.NET', 'XML', 'YAML',
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="F#">F#</button>
 | 
					                            ];
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Go">Go</button>
 | 
					                        @endphp
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Haskell">Haskell</button>
 | 
					
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="HTML">HTML</button>
 | 
					                        @foreach($languages as $language)
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="INI">INI</button>
 | 
					                            <div class="relative">
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Java">Java</button>
 | 
					                                <button type="button" refs="code-editor@language-button" data-favourite="false" data-lang="{{ strtolower($language) }}">{{ $language }}</button>
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="JavaScript">JavaScript</button>
 | 
					                                <button class="lang-option-favorite-toggle action-favourite" data-title="{{ trans('common.favourite') }}">@icon('star-outline')</button>
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="JSON">JSON</button>
 | 
					                                <button class="lang-option-favorite-toggle action-unfavourite" data-title="{{ trans('common.unfavourite') }}">@icon('star')</button>
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Julia">Julia</button>
 | 
					                            </div>
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="kotlin">Kotlin</button>
 | 
					                        @endforeach
 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="LaTeX">LaTeX</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Lua">Lua</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="MarkDown">MarkDown</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Nginx">Nginx</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="ocaml">OCaml</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="PASCAL">Pascal</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Perl">Perl</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="PHP">PHP</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Powershell">Powershell</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Python">Python</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="Ruby">Ruby</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="rust">Rust</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="shell">Shell/Bash</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="SQL">SQL</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="typescript">TypeScript</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="VBScript">VBScript</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="VB.NET">VB.NET</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="XML">XML</button>
 | 
					 | 
				
			||||||
                        <button type="button" refs="code-editor@languageLink" data-lang="YAML">YAML</button>
 | 
					 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                </div>
 | 
					                </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,6 +235,7 @@ Route::middleware('auth')->group(function () {
 | 
				
			||||||
    Route::patch('/settings/users/{id}/change-sort/{type}', [UserController::class, 'changeSort']);
 | 
					    Route::patch('/settings/users/{id}/change-sort/{type}', [UserController::class, 'changeSort']);
 | 
				
			||||||
    Route::patch('/settings/users/{id}/update-expansion-preference/{key}', [UserController::class, 'updateExpansionPreference']);
 | 
					    Route::patch('/settings/users/{id}/update-expansion-preference/{key}', [UserController::class, 'updateExpansionPreference']);
 | 
				
			||||||
    Route::patch('/settings/users/toggle-dark-mode', [UserController::class, 'toggleDarkMode']);
 | 
					    Route::patch('/settings/users/toggle-dark-mode', [UserController::class, 'toggleDarkMode']);
 | 
				
			||||||
 | 
					    Route::patch('/settings/users/update-code-language-favourite', [UserController::class, 'updateCodeLanguageFavourite']);
 | 
				
			||||||
    Route::post('/settings/users/create', [UserController::class, 'store']);
 | 
					    Route::post('/settings/users/create', [UserController::class, 'store']);
 | 
				
			||||||
    Route::get('/settings/users/{id}', [UserController::class, 'edit']);
 | 
					    Route::get('/settings/users/{id}', [UserController::class, 'edit']);
 | 
				
			||||||
    Route::put('/settings/users/{id}', [UserController::class, 'update']);
 | 
					    Route::put('/settings/users/{id}', [UserController::class, 'update']);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
namespace Tests\User;
 | 
					namespace Tests\User;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use BookStack\Entities\Models\Bookshelf;
 | 
					use BookStack\Entities\Models\Bookshelf;
 | 
				
			||||||
 | 
					use BookStack\Entities\Models\Page;
 | 
				
			||||||
use Tests\TestCase;
 | 
					use Tests\TestCase;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UserPreferencesTest extends TestCase
 | 
					class UserPreferencesTest extends TestCase
 | 
				
			||||||
| 
						 | 
					@ -150,4 +151,23 @@ class UserPreferencesTest extends TestCase
 | 
				
			||||||
            ->assertElementExists('.featured-image-container')
 | 
					            ->assertElementExists('.featured-image-container')
 | 
				
			||||||
            ->assertElementNotExists('.content-wrap .entity-list-item');
 | 
					            ->assertElementNotExists('.content-wrap .entity-list-item');
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function test_update_code_language_favourite()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $editor = $this->getEditor();
 | 
				
			||||||
 | 
					        $page = Page::query()->first();
 | 
				
			||||||
 | 
					        $this->actingAs($editor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->patch('/settings/users/update-code-language-favourite', ['language' => 'php', 'active' => true]);
 | 
				
			||||||
 | 
					        $this->patch('/settings/users/update-code-language-favourite', ['language' => 'javascript', 'active' => true]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $resp = $this->get($page->getUrl('/edit'));
 | 
				
			||||||
 | 
					        $resp->assertSee('option:code-editor:favourites="php,javascript"', false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $this->patch('/settings/users/update-code-language-favourite', ['language' => 'ruby', 'active' => true]);
 | 
				
			||||||
 | 
					        $this->patch('/settings/users/update-code-language-favourite', ['language' => 'php', 'active' => false]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $resp = $this->get($page->getUrl('/edit'));
 | 
				
			||||||
 | 
					        $resp->assertSee('option:code-editor:favourites="javascript,ruby"', false);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue