From 1629f712bc2b0294bccc4128e375c460a6ad9bca Mon Sep 17 00:00:00 2001
From: Kovah <mail@kovah.de>
Date: Thu, 10 Jan 2019 22:39:01 +0100
Subject: [PATCH] Implement bookmarklet feature (#5)

---
 app/Helper/LinkAce.php                        |  15 ++
 .../Controllers/App/BookmarkletController.php |  72 +++++++++
 .../App/UserSettingsController.php            |   8 +-
 app/Http/Controllers/Auth/LoginController.php |  13 +-
 .../Controllers/Models/LinkController.php     |  11 ++
 resources/assets/sass/custom/_layout.scss     |   2 +-
 resources/lang/en/linkace.php                 |   3 +
 resources/lang/en/settings.php                |   4 +
 .../actions/bookmarklet/complete.blade.php    |  26 ++++
 .../actions/bookmarklet/create.blade.php      |   7 +
 .../views/actions/bookmarklet/login.blade.php |  78 ++++++++++
 .../views/actions/settings/user.blade.php     |  19 ++-
 resources/views/layouts/bookmarklet.blade.php |  32 ++++
 .../views/models/links/_create-form.blade.php | 140 ++++++++++++++++++
 resources/views/models/links/create.blade.php | 138 +----------------
 routes/web.php                                |  24 +--
 16 files changed, 441 insertions(+), 151 deletions(-)
 create mode 100644 app/Http/Controllers/App/BookmarkletController.php
 create mode 100644 resources/views/actions/bookmarklet/complete.blade.php
 create mode 100644 resources/views/actions/bookmarklet/create.blade.php
 create mode 100644 resources/views/actions/bookmarklet/login.blade.php
 create mode 100644 resources/views/layouts/bookmarklet.blade.php
 create mode 100644 resources/views/models/links/_create-form.blade.php

diff --git a/app/Helper/LinkAce.php b/app/Helper/LinkAce.php
index 4ed52797..3f156ceb 100644
--- a/app/Helper/LinkAce.php
+++ b/app/Helper/LinkAce.php
@@ -11,6 +11,7 @@ class LinkAce
 {
     /**
      * Get the title of an HTML page b
+     *
      * @param string $url
      * @return string|string[]
      */
@@ -40,4 +41,18 @@ class LinkAce
 
         return $title;
     }
+
+    /**
+     * Generate the code for the bookmarklet
+     *
+     * @return mixed|string
+     */
+    public static function generateBookmarkletCode()
+    {
+        $bm_code = "javascript:javascript:(function(){var%20url%20=%20location.href;var%20title%20=%20document.title%20||%20url;window.open('##URL##?u='%20+%20encodeURIComponent(url)+'&t='%20+%20encodeURIComponent(title),'_blank','menubar=no,height=720,width=600,toolbar=no,scrollbars=yes,status=no,dialog=1');})();";
+
+        $bm_code = str_replace('##URL##', route('bookmarklet-add'), $bm_code);
+
+        return $bm_code;
+    }
 }
diff --git a/app/Http/Controllers/App/BookmarkletController.php b/app/Http/Controllers/App/BookmarkletController.php
new file mode 100644
index 00000000..f5dc2af3
--- /dev/null
+++ b/app/Http/Controllers/App/BookmarkletController.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace App\Http\Controllers\App;
+
+use App\Http\Controllers\Controller;
+use App\Models\Category;
+use Illuminate\Http\Request;
+
+class BookmarkletController extends Controller
+{
+    /**
+     * Show the application dashboard.
+     *
+     * @param Request $request
+     * @return \Illuminate\Http\Response
+     */
+    public function getLinkAddForm(Request $request)
+    {
+        $new_url = $request->get('u');
+        $new_title = $request->get('t');
+
+        // Rredirect to the login if the user is not logged in
+        if (!auth()->check()) {
+            // Save details for the link in the session
+            session(['bookmarklet.new_url' => $new_url]);
+            session(['bookmarklet.new_title' => $new_title]);
+            session(['bookmarklet.login_redirect' => true]);
+
+            return redirect()->route('bookmarklet-login');
+        }
+
+        if ($new_url === null) {
+            // Receive the link details from the session
+            $new_url = session('bookmarklet.new_url');
+            $new_title = session('bookmarklet.new_title');
+
+            session()->remove('bookmarklet.new_url');
+            session()->remove('bookmarklet.new_title');
+        }
+
+        session(['bookmarklet.create' => true]);
+
+        return view('actions.bookmarklet.create')
+            ->with('bookmark_url', $new_url)
+            ->with('bookmark_title', $new_title)
+            ->with('categories', Category::parentOnly()
+                ->byUser(auth()->user()->id)
+                ->orderBy('name', 'asc')
+                ->get()
+            );
+    }
+
+    /**
+     * Show the application dashboard.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function getCompleteView()
+    {
+        return view('actions.bookmarklet.complete');
+    }
+
+    /**
+     * Show the application dashboard.
+     *
+     * @return \Illuminate\Http\Response
+     */
+    public function getLoginForm()
+    {
+        return view('actions.bookmarklet.login');
+    }
+}
diff --git a/app/Http/Controllers/App/UserSettingsController.php b/app/Http/Controllers/App/UserSettingsController.php
index 36b7858a..a78b61ec 100644
--- a/app/Http/Controllers/App/UserSettingsController.php
+++ b/app/Http/Controllers/App/UserSettingsController.php
@@ -2,6 +2,7 @@
 
 namespace App\Http\Controllers\App;
 
+use App\Helper\LinkAce;
 use App\Http\Controllers\Controller;
 use App\Http\Requests\UserSettingsUpdateRequest;
 use App\Models\Setting;
@@ -22,7 +23,12 @@ class UserSettingsController extends Controller
      */
     public function getUserSettings()
     {
-        return view('actions.settings.user', ['user' => auth()->user()]);
+        $bookmarklet_code = LinkAce::generateBookmarkletCode();
+
+        return view('actions.settings.user', [
+            'user' => auth()->user(),
+            'bookmarklet_code' => $bookmarklet_code,
+        ]);
     }
 
     /**
diff --git a/app/Http/Controllers/Auth/LoginController.php b/app/Http/Controllers/Auth/LoginController.php
index 3a1f70b8..5a2f345a 100644
--- a/app/Http/Controllers/Auth/LoginController.php
+++ b/app/Http/Controllers/Auth/LoginController.php
@@ -23,9 +23,18 @@ class LoginController extends Controller
     /**
      * Where to redirect users after login.
      *
-     * @var string
+     * @return string
      */
-    protected $redirectTo = '/dashboard';
+    protected function redirectTo()
+    {
+        // Redirect to the bookmarklet form after login from the bookmarklet
+        if (session('bookmarklet.login_redirect')) {
+            session()->remove('bookmarklet.login_redirect');
+            return route('bookmarklet-add');
+        }
+
+        return '/dashboard';
+    }
 
     /**
      * Create a new controller instance.
diff --git a/app/Http/Controllers/Models/LinkController.php b/app/Http/Controllers/Models/LinkController.php
index 2312b35f..a59b429b 100644
--- a/app/Http/Controllers/Models/LinkController.php
+++ b/app/Http/Controllers/Models/LinkController.php
@@ -79,11 +79,22 @@ class LinkController extends Controller
 
         alert(trans('link.added_successfully'), 'success');
 
+        $is_bookmarklet = session('bookmarklet.create');
+
         if ($request->get('reload_view')) {
             session()->flash('reload_view', true);
+
+            if ($is_bookmarklet) {
+                return redirect()->route('bookmarklet-add');
+            }
+
             return redirect()->route('links.create');
         }
 
+        if ($is_bookmarklet) {
+            return redirect()->route('bookmarklet-complete');
+        }
+
         return redirect()->route('links.show', [$link->id]);
     }
 
diff --git a/resources/assets/sass/custom/_layout.scss b/resources/assets/sass/custom/_layout.scss
index 7a89d955..f8410678 100644
--- a/resources/assets/sass/custom/_layout.scss
+++ b/resources/assets/sass/custom/_layout.scss
@@ -1,5 +1,5 @@
 // Layout styles
-body {
+body:not(.bookmarklet) {
     padding-top: $nav-link-height + ($navbar-padding-y * 2);
 }
 
diff --git a/resources/lang/en/linkace.php b/resources/lang/en/linkace.php
index a3b7a70c..5b6be7cf 100644
--- a/resources/lang/en/linkace.php
+++ b/resources/lang/en/linkace.php
@@ -36,4 +36,7 @@ return [
     'no' => 'No',
 
     'no_results_found' => 'No :model found.',
+
+    'bookmarklet_close' => 'This bookmarklet window automatically closes in <span class="bm-timer">5</span> seconds.',
+    'open_linkace' => 'Open LinkAce',
 ];
diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php
index 09d56233..fbf1f0d0 100644
--- a/resources/lang/en/settings.php
+++ b/resources/lang/en/settings.php
@@ -13,6 +13,10 @@ return [
     'save_settings' => 'Save Settings',
     'settings_saved' => 'Settings successfully updated!',
 
+    'bookmarklet' => 'Bookmarklet',
+    'bookmarklet_button' => 'Drag this to your Bookmarks or right-click and save it as a bookmark',
+    'bookmarklet_help' => 'Add this Bookmarklet to your browser to quickly add links from the sites you visit without having to open LinkAce manually.',
+
     'change_password' => 'Change Password',
     'old_password' => 'Old Password',
     'new_password' => 'New Password',
diff --git a/resources/views/actions/bookmarklet/complete.blade.php b/resources/views/actions/bookmarklet/complete.blade.php
new file mode 100644
index 00000000..59935357
--- /dev/null
+++ b/resources/views/actions/bookmarklet/complete.blade.php
@@ -0,0 +1,26 @@
+@extends('layouts.bookmarklet')
+
+@section('content')
+
+    <div class="mt-3">
+        <p>@lang('linkace.bookmarklet_close')</p>
+
+        <a href="{{ route('front') }}" target="_blank" class="btn btn-primary">
+            <i class="fa fa-arrow-left fa-mr"></i>
+            @lang('linkace.open_linkace')
+        </a>
+    </div>
+
+@endsection
+
+@push('scripts')
+    <script>
+        var timer = $('.bm-timer');
+        window.setInterval(function () {
+            timer.text(parseInt(timer.text()) - 1);
+        }, 1000);
+        window.setTimeout(function () {
+            window.close();
+        }, 5000);
+    </script>
+@endpush
diff --git a/resources/views/actions/bookmarklet/create.blade.php b/resources/views/actions/bookmarklet/create.blade.php
new file mode 100644
index 00000000..70f7035a
--- /dev/null
+++ b/resources/views/actions/bookmarklet/create.blade.php
@@ -0,0 +1,7 @@
+@extends('layouts.bookmarklet')
+
+@section('content')
+
+    @include('models.links._create-form')
+
+@endsection
diff --git a/resources/views/actions/bookmarklet/login.blade.php b/resources/views/actions/bookmarklet/login.blade.php
new file mode 100644
index 00000000..30cc60e3
--- /dev/null
+++ b/resources/views/actions/bookmarklet/login.blade.php
@@ -0,0 +1,78 @@
+@extends('layouts.bookmarklet')
+
+@section('content')
+
+    <div class="card">
+        <div class="card-header">
+            @lang('linkace.login')
+        </div>
+        <div class="card-body">
+            <form method="POST" action="{{ route('login') }}" aria-label="@lang('linkace.login')">
+                @csrf
+
+                <div class="form-group">
+                    <div class="input-group mb-3">
+                        <div class="input-group-prepend">
+                            <div class="input-group-text">
+                                <i class="fa fa-fw fa-envelope"></i>
+                            </div>
+                        </div>
+                        <input type="email" name="email" id="email" class="form-control"
+                            value="{{ old('email') }}"
+                            placeholder="@lang('linkace.email')" aria-label="@lang('linkace.email')" required
+                            autofocus>
+                    </div>
+
+                    @if ($errors->has('email'))
+                        <p class="invalid-feedback" role="alert">
+                            {{ $errors->first('email') }}
+                        </p>
+                    @endif
+                </div>
+
+                <div class="form-group">
+                    <div class="input-group mb-3">
+                        <div class="input-group-prepend">
+                            <div class="input-group-text">
+                                <i class="fa fa-fw fa-lock"></i>
+                            </div>
+                        </div>
+                        <input type="password" name="password" id="password" class="form-control"
+                            placeholder="@lang('linkace.password')" aria-label="@lang('linkace.password')">
+                    </div>
+                    @if ($errors->has('password'))
+                        <p class="invalid-feedback" role="alert">
+                            {{ $errors->first('password') }}
+                        </p>
+                    @endif
+                </div>
+
+                <div class="row mt-4">
+                    <div class="col-8">
+
+                        <div class="custom-control custom-checkbox pt-1">
+                            <input type="hidden" name="remember_me" value="0">
+                            <input type="checkbox" class="custom-control-input" id="remember_me"
+                                @if(old('remember_me')) checked @endif>
+
+                            <label class="custom-control-label" for="remember_me">
+                                @lang('linkace.remember_me')
+                            </label>
+                        </div>
+
+                    </div>
+                    <div class="col-4">
+
+                        <button type="submit" class="btn btn-primary btn-block">
+                            @lang('linkace.login')
+                        </button>
+
+                    </div>
+                </div>
+
+            </form>
+        </div>
+    </div>
+
+
+@endsection
diff --git a/resources/views/actions/settings/user.blade.php b/resources/views/actions/settings/user.blade.php
index 424ea63d..d1bb6112 100644
--- a/resources/views/actions/settings/user.blade.php
+++ b/resources/views/actions/settings/user.blade.php
@@ -3,6 +3,23 @@
 @section('content')
 
     <div class="card">
+        <div class="card-header">
+            @lang('settings.bookmarklet')
+        </div>
+        <div class="card-body">
+
+            <p>@lang('settings.bookmarklet_help')</p>
+
+            <a href="{{ $bookmarklet_code }}" class="btn btn-primary">
+                @lang('settings.bookmarklet')
+            </a>
+
+            <p class="small">@lang('settings.bookmarklet_button')</p>
+
+        </div>
+    </div>
+
+    <div class="card mt-4">
         <div class="card-header">
             @lang('settings.user_settings')
         </div>
@@ -164,7 +181,7 @@
         </div>
     </div>
 
-    <div class="card mt-5">
+    <div class="card mt-4">
         <div class="card-header">
             @lang('settings.change_password')
         </div>
diff --git a/resources/views/layouts/bookmarklet.blade.php b/resources/views/layouts/bookmarklet.blade.php
new file mode 100644
index 00000000..c8594577
--- /dev/null
+++ b/resources/views/layouts/bookmarklet.blade.php
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+
+    <meta name="csrf-token" content="{{ csrf_token() }}">
+
+    <title>{{ config('app.name', 'LinkAce') }}</title>
+
+    <link href="{{ asset('assets/app.css') }}" rel="stylesheet">
+</head>
+<body class="bookmarklet">
+<div id="app">
+
+    <main class="main container">
+        <div class="mb-3 text-center">
+            <img src="{{ asset('assets/img/logo_linkace.svg') }}" alt="@lang('linkace.linkace')"
+                width="81" height="30">
+        </div>
+
+        @include('partials.alerts')
+        @yield('content')
+    </main>
+
+    <script src="{{ asset('assets/dependencies.js') }}"></script>
+    @stack('scripts')
+
+</div>
+</body>
+</html>
diff --git a/resources/views/models/links/_create-form.blade.php b/resources/views/models/links/_create-form.blade.php
new file mode 100644
index 00000000..b24a590f
--- /dev/null
+++ b/resources/views/models/links/_create-form.blade.php
@@ -0,0 +1,140 @@
+<div class="card">
+    <header class="card-header">
+        @lang('link.add')
+    </header>
+    <div class="card-body">
+
+        <form action="{{ route('links.store') }}" method="POST">
+            @csrf
+
+            <div class="form-group">
+                <label class="label" for="url">@lang('link.url')</label>
+                <input name="url" id="url" type="url"
+                    class="form-control form-control-lg{{ $errors->has('url') ? ' is-invalid' : '' }}"
+                    placeholder="@lang('link.url')" value="{{ old('url') ?: $bookmark_url ?? '' }}"
+                    required autofocus>
+                @if ($errors->has('url'))
+                    <p class="invalid-feedback" role="alert">
+                        {{ $errors->first('url') }}
+                    </p>
+                @endif
+            </div>
+
+            <div class="row">
+                <div class="col">
+
+                    <div class="form-group">
+                        <label class="label" for="title">@lang('link.title')</label>
+                        <input name="title" id="title"
+                            class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}"
+                            type="text" placeholder="@lang('link.title')"
+                            value="{{ old('title') ?: $bookmark_title ?? '' }}">
+                        @if ($errors->has('title'))
+                            <p class="invalid-feedback" role="alert">
+                                {{ $errors->first('title') }}
+                            </p>
+                        @endif
+                    </div>
+
+                    <div class="form-group">
+                        <label for="description">@lang('link.description')</label>
+                        <textarea name="description" id="description" rows="4" class="form-control"
+                            placeholder="@lang('link.description')">{{ old('description') }}</textarea>
+
+                        @if ($errors->has('description'))
+                            <p class="invalid-feedback" role="alert">
+                                {{ $errors->first('description') }}
+                            </p>
+                        @endif
+                    </div>
+
+                </div>
+                <div class="col">
+
+                    <div class="form-group">
+                        <label for="category_id">@lang('category.category')</label>
+                        <select id="category_id" name="category_id"
+                            class="custom-select{{ $errors->has('category_id') ? ' is-invalid' : '' }}">
+                            <option value="0">@lang('category.select_category')</option>
+                            @foreach($categories as $category)
+                                <option value="{{ $category->id }}">
+                                    {{ $category->name }}
+                                </option>
+                                @if($category->childCategories)
+                                    @foreach($category->childCategories as $child_category)
+                                        <option value="{{ $child_category->id }}">
+                                            &rightarrow; {{ $child_category->name }}
+                                        </option>
+                                    @endforeach
+                                @endif
+                            @endforeach
+                        </select>
+
+
+                        @if ($errors->has('category_id'))
+                            <p class="invalid-feedback" role="alert">
+                                {{ $errors->first('category_id') }}
+                            </p>
+                        @endif
+                    </div>
+
+                    <div class="form-group">
+                        <label for="tags">@lang('tag.tags')</label>
+                        <input name="tags" id="tags" type="text" placeholder="@lang('tag.tags')"
+                            value="{{ old('tags') }}">
+
+                        @if ($errors->has('url'))
+                            <p class="invalid-feedback" role="alert">
+                                {{ $errors->first('tags') }}
+                            </p>
+                        @endif
+                    </div>
+
+                    <div class="form-group">
+                        <label for="is_private">@lang('linkace.is_private')</label>
+                        <select id="is_private" name="is_private"
+                            class="custom-select{{ $errors->has('is_private') ? ' is-invalid' : '' }}">
+                            <option value="0">
+                                @lang('linkace.no')
+                            </option>
+                            <option value="1" @if(usersettings('private_default') === '1') selected @endif>
+                                @lang('linkace.yes')
+                            </option>
+                        </select>
+
+                        @if ($errors->has('is_private'))
+                            <p class="invalid-feedback" role="alert">
+                                {{ $errors->first('is_private') }}
+                            </p>
+                        @endif
+                    </div>
+
+                </div>
+            </div>
+
+            <div class="mt-3 d-flex align-items-center">
+
+                @if(!isset($bookmark_url))
+                    <div class="custom-control custom-checkbox ml-auto mr-4">
+                        <input class="custom-control-input" type="checkbox" id="reload_view" name="reload_view"
+                            @if(session('reload_view')) checked @endif>
+                        <label class="custom-control-label" for="reload_view">
+                            @lang('linkace.continue_adding')
+                        </label>
+                    </div>
+                @endif
+
+                <button type="submit" class="btn btn-primary">
+                    <i class="fa fa-save fa-mr"></i> @lang('link.add')
+                </button>
+
+            </div>
+
+        </form>
+
+    </div>
+</div>
+
+@push('scripts')
+    @include('models.links._tags-js')
+@endpush
diff --git a/resources/views/models/links/create.blade.php b/resources/views/models/links/create.blade.php
index 86065e62..489731f8 100644
--- a/resources/views/models/links/create.blade.php
+++ b/resources/views/models/links/create.blade.php
@@ -2,142 +2,6 @@
 
 @section('content')
 
-    <div class="card">
-        <header class="card-header">
-            @lang('link.add')
-        </header>
-        <div class="card-body">
-
-            <form action="{{ route('links.store') }}" method="POST">
-                @csrf
-
-                <div class="form-group">
-                    <label class="label" for="url">@lang('link.url')</label>
-                    <input name="url" id="url" type="url"
-                        class="form-control form-control-lg{{ $errors->has('url') ? ' is-invalid' : '' }}"
-                        placeholder="@lang('link.url')" value="{{ old('url') }}"
-                        required autofocus>
-                    @if ($errors->has('url'))
-                        <p class="invalid-feedback" role="alert">
-                            {{ $errors->first('url') }}
-                        </p>
-                    @endif
-                </div>
-
-                <div class="row">
-                    <div class="col">
-
-                        <div class="form-group">
-                            <label class="label" for="title">@lang('link.title')</label>
-                            <input name="title" id="title"
-                                class="form-control{{ $errors->has('title') ? ' is-invalid' : '' }}"
-                                type="text" placeholder="@lang('link.title')" value="{{ old('title') }}">
-                            @if ($errors->has('title'))
-                                <p class="invalid-feedback" role="alert">
-                                    {{ $errors->first('title') }}
-                                </p>
-                            @endif
-                        </div>
-
-                        <div class="form-group">
-                            <label for="description">@lang('link.description')</label>
-                            <textarea name="description" id="description" rows="4" class="form-control"
-                                placeholder="@lang('link.description')">{{ old('description') }}</textarea>
-
-                            @if ($errors->has('description'))
-                                <p class="invalid-feedback" role="alert">
-                                    {{ $errors->first('description') }}
-                                </p>
-                            @endif
-                        </div>
-
-                    </div>
-                    <div class="col">
-
-                        <div class="form-group">
-                            <label for="category_id">@lang('category.category')</label>
-                            <select id="category_id" name="category_id"
-                                class="custom-select{{ $errors->has('category_id') ? ' is-invalid' : '' }}">
-                                <option value="0">@lang('category.select_category')</option>
-                                @foreach($categories as $category)
-                                    <option value="{{ $category->id }}">
-                                        {{ $category->name }}
-                                    </option>
-                                    @if($category->childCategories)
-                                        @foreach($category->childCategories as $child_category)
-                                            <option value="{{ $child_category->id }}">
-                                                &rightarrow; {{ $child_category->name }}
-                                            </option>
-                                        @endforeach
-                                    @endif
-                                @endforeach
-                            </select>
-
-
-                            @if ($errors->has('category_id'))
-                                <p class="invalid-feedback" role="alert">
-                                    {{ $errors->first('category_id') }}
-                                </p>
-                            @endif
-                        </div>
-
-                        <div class="form-group">
-                            <label for="tags">@lang('tag.tags')</label>
-                            <input name="tags" id="tags" type="text" placeholder="@lang('tag.tags')"
-                                value="{{ old('tags') }}">
-
-                            @if ($errors->has('url'))
-                                <p class="invalid-feedback" role="alert">
-                                    {{ $errors->first('tags') }}
-                                </p>
-                            @endif
-                        </div>
-
-                        <div class="form-group">
-                            <label for="is_private">@lang('linkace.is_private')</label>
-                            <select id="is_private" name="is_private"
-                                class="custom-select{{ $errors->has('is_private') ? ' is-invalid' : '' }}">
-                                <option value="0">
-                                    @lang('linkace.no')
-                                </option>
-                                <option value="1" @if(usersettings('private_default') === '1') selected @endif>
-                                    @lang('linkace.yes')
-                                </option>
-                            </select>
-
-                            @if ($errors->has('is_private'))
-                                <p class="invalid-feedback" role="alert">
-                                    {{ $errors->first('is_private') }}
-                                </p>
-                            @endif
-                        </div>
-
-                    </div>
-                </div>
-
-                <div class="mt-3 d-flex align-items-center">
-
-                    <div class="custom-control custom-checkbox ml-auto mr-4">
-                        <input class="custom-control-input" type="checkbox" id="reload_view" name="reload_view"
-                            @if(session('reload_view')) checked @endif>
-                        <label class="custom-control-label" for="reload_view">
-                            @lang('linkace.continue_adding')
-                        </label>
-                    </div>
-
-                    <button type="submit" class="btn btn-primary">
-                        <i class="fa fa-save fa-mr"></i> @lang('link.add')
-                    </button>
-
-                </div>
-
-            </form>
-
-        </div>
-    </div>
-
-    @push('scripts')
-        @include('models.links._tags-js')
-    @endpush
+    @include('models.links._create-form')
 
 @endsection
diff --git a/routes/web.php b/routes/web.php
index 8dccc039..e56aef81 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -20,19 +20,25 @@ Route::get('/', function () {
 })->name('front');
 
 // Authentication Routes
-$this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
-$this->post('login', 'Auth\LoginController@login');
-$this->post('logout', 'Auth\LoginController@logout')->name('logout');
+Route::get('login', 'Auth\LoginController@showLoginForm')->name('login');
+Route::post('login', 'Auth\LoginController@login');
+Route::post('logout', 'Auth\LoginController@logout')->name('logout');
 
 // Registration Routes (disabled, use the `artisan registeruser` command)
-//$this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
-//$this->post('register', 'Auth\RegisterController@register');
+//Route::get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
+//Route::post('register', 'Auth\RegisterController@register');
 
 // Password Reset Routes
-$this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
-$this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
-$this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
-$this->post('password/reset', 'Auth\ResetPasswordController@reset');
+Route::get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
+Route::post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
+Route::get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
+Route::post('password/reset', 'Auth\ResetPasswordController@reset');
+
+Route::prefix('bookmarklet')->group(function () {
+    Route::get('add', 'App\BookmarkletController@getLinkAddForm')->name('bookmarklet-add');
+    Route::get('show', 'App\BookmarkletController@getCompleteView')->name('bookmarklet-complete');
+    Route::get('login', 'App\BookmarkletController@getLoginForm')->name('bookmarklet-login');
+});
 
 // Model routes
 Route::group(['middleware' => ['auth']], function () {