Прокачиваем собственный текстовый редактор
vk f t

Прокачиваем собственный текстовый редактор

Добав­ля­ем под­держ­ку неогра­ни­чен­но­го чис­ла доку­мен­тов, новое оформ­ле­ние и без­гра­нич­ные воз­мож­но­сти настрой­ки.

Наста­ло вре­мя доде­лать наш тек­сто­вый редак­тор и доба­вить в него воз­мож­ность рабо­ты с несколь­ки­ми доку­мен­та­ми. Если вы не зна­е­те, о чём идёт речь — про­чи­тай­те наши ста­тьи о том, как сде­лать редак­тор с авто­со­хра­не­ни­ем тек­ста, и как улуч­шить его внеш­ний вид.

Алго­ритм будет такой:

Что­бы не тра­тить вре­мя и силы зря, исполь­зу­ем для спис­ка доку­мен­тов уже гото­вый код из ста­тьи про спи­сок задач. Мы объ­еди­ним эти две про­грам­мы в одну — про­грам­ми­сты часто поль­зу­ют­ся этим под­хо­дом, что­бы быст­ро полу­чить нуж­ный резуль­тат.

Код редак­то­ра из преды­ду­щей ста­тьи

    
language: HTML
{

<html>

 

<!-- служебная часть -->

<head>

  <!-- заголовок страницы -->

  <title>Текстовый редактор</title>

 

  <!-- настраиваем служебную информацию для браузеров -->

  <meta charset="utf-8">

  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <meta name="viewport" content="width=device-width, initial-scale=1">

 

  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->

  <style type="text/css">

 

    /*задаём общие параметры для всей страницы: шрифт и отступы*/

    body{

      text-align: left;

      margin: 10;

      font-family: Courier New, Courier;

      font-size: 20px;

      background-color: lightgray;

    }

 

    /* оформляем окно редактора */

    .editorSheet{

      width: 80vw;

      min-height: 100vw;

      margin-left: 10vw;

      border: solid; 

      border-width: 0px; 

      text-align: left;

      background-color: white;

      -webkit-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      -moz-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      padding: 15px;

    }

 

    h1{

        font-size: 40px;

        font-family: Tahoma;

        font-weight: 900;

    }

 

  /*закончили со стилями*/

  </style>

 

<!-- закрываем служебную часть страницы -->

</head>

 

<!-- началось содержимое страницы -->

<body>

 

  <!-- началась видимая часть -->

  

  <!-- заголовок страницы -->

  <h1>Текстовый редактор с автосохранением</h1>

 

  <!-- большой блок для ввода текста: высота в половину, а ширина — во весь экран, назвывается "text_area", обведено рамкой толщиной в 1 пиксель, выравнивание текста — по левому краю -->

  <div id="editor" contenteditable="true" class="editorSheet">

  </div>

 

 

  <!-- закончилась видимая часть -->

 

  <!-- пишем скрипт, который будет постоянно сохранять наш текст -->

  <script>

    

    // если в нашем хранилище уже что-то есть…

    if (localStorage.getItem('text_in_editor') !== null) {

 

        // …то отображаем его содержимое в нашем редакторе

        document.getElementById('editor').innerHTML = localStorage.getItem('text_in_editor');

      }

       

    // отслеживаем каждое нажатие клавиши и при каждом нажатии выполняем команду

    document.addEventListener('keydown', function(e) {

    

      // записываем содержимое нашего редактора в хранилище

      localStorage.setItem('text_in_editor', document.getElementById('editor').innerHTML);

    });

 

  // закончился скрипт

  </script>

 

<!-- закончилось содержимое страницы -->

</body>

 

<!-- конец всего HTML-документа -->

</html>


Ско­пи­ро­вать код
Код ско­пи­ро­ван

Добавляем список документов

Сде­ла­ем наш спи­сок доку­мен­тов сле­ва, но настро­им его пове­де­ние таким обра­зом, что­бы на малень­ких экра­нах он зани­мал всю шири­ну бра­у­зе­ра. Исполь­зу­ем для это­го Бут­страп, с кото­рым мы уже позна­ко­ми­лись, — он сам за нас сде­ла­ет всю рабо­ту по адап­тив­ной вёрст­ке. Сна­ча­ла под­клю­чим его:

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

Теперь изме­ним код заго­лов­ка стра­ни­цы — поло­жим его в отдель­ный кон­тей­нер и зада­дим раз­ме­ры:

<div class="container" >
    <div class="row">
      <!-- делаем заголовок -->
      <div class="col-12">
        <h1 id="h1_name">Текстовый редактор с автосохранением</h1>
      </div>
    </div>
  </div>

Затем сде­ла­ем спи­сок доку­мен­тов. Для это­го мы вос­поль­зу­ем­ся сво­им же гото­вым кодом из ста­тьи про спи­сок задач и адап­ти­ру­ем его под наши цели — меня­ем текст, обо­ра­чи­ва­ем код в новый кон­тей­нер и зада­ём раз­мер бло­ков для каж­до­го раз­ме­ра экра­на. Ниже тоже дела­ем отдель­ный блок с окном редак­то­ра, у кото­ро­го раз­ме­ры свои:

    
language: HTML
{

<div class="container" >

  <div class="row">

 

    <div class="col-12 col-sm-12 col-md-4 col-lg-3 col-xl-3">

        

      <!-- делаем боковой список с названиями документов-->

        <!-- заголовок списка  -->

        <h2>Документы</h2>

        <p style="font-size: 14px">Alt + клик — удаляет документ</p>

 

        <!-- поле ввода, куда пишем название новых документов -->

        <div id="tdlApp">

          <input type="text" class="form-control" placeholder="Новый документ">

         

         <!-- создаём пока ещё пустой список -->

          <div class="tdlDiv">

 

            <ul class="List list-unstyled">

              <!-- тут появятся наши названия документов, когда мы их добавим -->

            </ul>

 

          </div>

        </div>

      <!-- закончили с оформлением списка -->

 

    </div>

 

    <!-- делаем само окно редактора, где пишем весь текст -->

    <div class="col-12 col-sm-12 col-md-8 col-lg-9 col-xl-9">

 

      <div id="editor" contenteditable="true" class="editorSheet">

      </div>

 

    </div>

 

  </div>

</div>


Ско­пи­ро­вать код
Код ско­пи­ро­ван

Как види­те, мы взя­ли наш ста­рый рабо­чий код, немно­го поме­ня­ли текст в заго­лов­ках, доба­ви­ли фрейм­ворк и исполь­зо­ва­ли в новой про­грам­ме. Быст­ро и удоб­но.

Настраиваем внешний вид

Раз мы доба­ви­ли новые теги и сти­ли, нуж­но их про­пи­сать в раз­де­ле <style>. Если это­го не сде­лать, бра­у­зер не пой­мёт, как с ними рабо­тать, и про­грам­ма будет делать не то, что нам нуж­но. Как и рань­ше, мы объ­еди­ня­ем сти­ли двух ста­рых про­грамм в один и слег­ка меня­ем их:

    
language: CSS
{

/*задаём общие параметры для всей страницы: шрифт и отступы*/

    body{

      text-align: left;

      margin: 10;

      font-family: Courier New, Courier;

      font-size: 20px;

      background-color: lightgray;

    } 

 

    /* оформляем окно редактора */

    .editorSheet{

      min-height: 65vw;

      border: solid; 

      border-width: 0px; 

      text-align: left;

      background-color: white;

      -webkit-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      -moz-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      padding: 15px;

      border-style: solid;

      border-width: 1px;

    } 

 

    /* стиль заголовка h1*/

    h1{

      font-size: 40px;

      font-family: Tahoma;

      font-weight: 900;

      padding-bottom: 30px;

    } 

 

    /* стиль заголовка h2*/

    h2{

      font-size: 25px;

      font-family: Arial;

      font-weight: 900;

      color: black;

      font-weight: 400;

      } 

 

    /* настраиваем внешний вид поля ввода*/

    input{

      display: inline-block;

      margin: 20px auto;

      border: 2px solid #eee;

      padding: 10px 20px;

      font-family: Verdana, Arial, sans-serif;

      font-size: 13px;

    } 

 

    /*как будет выглядеть каждый элемент нашего списка документов*/

    .tdItem{

      text-align: left;

      padding: 10px;

      cursor: default;

      border-radius: 7px;

      font-size: 16px;

    } 

    

    /*что произойдёт, когда мы наведём курсор на название документа в списке*/

    .tdItem:hover{

      background-color: lightblue;

    }


Ско­пи­ро­вать код
Код ско­пи­ро­ван

Сохра­ня­ем изме­не­ния в исход­ном коде наше­го редак­то­ра, обнов­ля­ем и смот­рим на резуль­тат:


Собираем скрипт

Глав­ная зада­ча в скрип­те — посто­ян­но отсле­жи­вать откры­тый доку­мент и пока­зы­вать его содер­жи­мое. Для это­го заве­дём пере­мен­ную N_store, где будем хра­нить внут­рен­ний номер доку­мен­та. Осталь­ное как обыч­но — соби­ра­ем один скрипт из двух гото­вых:

    
language: Javascript
{

// заводим переменные под наши задачи

    var List = $('#tdlApp ul');

    var Mask = 'tdl_';

 

    // тут будем хранить внутренний номер документа, чтобы связать список и текст в редакторе

    var N_store;

    

    // отслеживаем каждое нажатие клавиши в редакторе и при каждом нажатии выполняем команду

    document.addEventListener('keydown', function(e) {

    

      // записываем содержимое нашего редактора в хранилище, при этом ячейка связана с текущим документом

      localStorage.setItem(N_store + 'text_in_editor', document.getElementById('editor').innerHTML);

    } );

 

    // функция, которая берёт из памяти наши документы и делает из них список

    function showTasks( ){

 

      // временно скрываем окно редактора

      document.getElementById('editor').style.display = "none";

 

      // узнаём размер хранилища

      var Storage_size = localStorage.length;

 

      // если в хранилище что-то есть…

      if (Storage_size > 0){

 

        // то берём и добавляем это в список документов 

        for (var i = 0; i < Storage_size; i++){

          var key = localStorage.key(i);

          if(key.indexOf(Mask) == 0){

 

            // запоминаем внутренний номер документа, чтобы правильно показать текст в редакторе

            N_store = key[4];

 

            // делаем содержимое хранилища элементами списка

            $('<li></li>').addClass('tdItem')

              .attr('data-itemid', key)

              .text(localStorage.getItem(key))

              .appendTo(List);

          } 

        }  

      }  

    } 

 

    // сразу вызываем эту функцию, вдруг в памяти уже остались документы с прошлого раза

    showTasks();

 

    // следим, когда пользователь напишет название нового документа в поле ввода и нажмёт Enter

    $('#tdlApp input').on('keydown',function(e){

      if(e.keyCode != 13) return;

 

      var str = e.target.value;

      e.target.value = "";

 

      // если в поле ввода было что-то написано — начинаем обрабатывать

      if(str.length > 0){

        var number_Id = 0;

 

        List.children().each(function(index, el){

          var element_Id = $(el).attr('data-itemid').slice(4);

          if(element_Id > number_Id)

            number_Id = element_Id;

        } )

        number_Id++;

        

        // отправляем новый документ сразу в память

        localStorage.setItem(Mask+number_Id,str);

 

        // готовим для него новое поле редактора

        // берём текущий внутренний номер документа

        N_store = number_Id;

 

        // отправляем в память 

        localStorage.setItem(N_store + 'text_in_editor','');

 

        // делаем окно редактора видимым и очищаем текст в нём

        document.getElementById('editor').innerHTML = '';

        document.getElementById('editor').style.display = "block";

 

        // добавляем название документа в конец списка

        $('<li></li>').addClass('tdItem')

          .attr('data-itemid', Mask+number_Id)

          .text(str).appendTo(List);

 

        // меняем заголовок редактора

        document.getElementById('h1_name').innerHTML = localStorage.getItem('tdl_' + N_store);

      } 

    } );


Ско­пи­ро­вать код
Код ско­пи­ро­ван

Теперь оста­лось самое инте­рес­ное — обра­ба­ты­вать раз­ные кли­ки на назва­нии доку­мен­тов в спис­ке. Что­бы раз­ли­чать клик с нажа­тым Аль­том и без него, исполь­зу­ем свой­ство <event.altKey> — оно пока­жет, был ли Альт нажат в момент собы­тия. Если да — уда­ля­ем доку­мент. В той же функ­ции обра­бо­та­ем и про­стой клик по назва­нию:

    
language: Javascript
{

// при клике на названии документа — делаем его активным и даём с ним работать

    $(document).on('click','.tdItem', function(e){

 

      // находим документ, по которому кликнули

      var jet = $(e.target);

 

      // если при клике был нажат Atl

      if (event.altKey) {

 

        // то убираем документ из памяти

        localStorage.removeItem(jet.attr('data-itemid'));

        localStorage.removeItem(jet.attr('data-itemid')[4] + 'text_in_editor');

 

        // очищаем и скрываем окно редактора

        document.getElementById('editor').innerHTML = '';

        document.getElementById('editor').style.display = "none";

 

        // меняем заголовок редактора

        document.getElementById('h1_name').innerHTML = 'Текстовый редактор с автосохранением';

 

        // и убираем документ из списка

        jet.remove();

 

        // выходим из функции, чтобы не обрабатывать обычный клик

        return true;

      } 

 

      // обрабатываем обычный клик — делаем документ активным

      // получаем внутренний номер документа

      N_store = jet.attr('data-itemid')[4];

      

      // делаем окно редактора видимым и заполняем его содержимым из памяти

      document.getElementById('editor').style.display = "block";

      document.getElementById('editor').innerHTML = localStorage.getItem(N_store + 'text_in_editor');

 

      // меняем заголовок редактора

      document.getElementById('h1_name').innerHTML = localStorage.getItem('tdl_' + N_store);

       

    } )


Ско­пи­ро­вать код
Код ско­пи­ро­ван

Соби­ра­ем всё в один файл и про­ве­ря­ем, что у нас под­клю­чён jQuery, кото­рый и отве­ча­ет почти за всю магию рабо­ты с эле­мен­та­ми на стра­ни­це. Обнов­ля­ем и насла­жда­ем­ся резуль­та­том:


Общий код страницы

    
language: HTML
{

<html>

 

<!-- служебная часть -->

<head>

  <!-- заголовок страницы -->

  <title>Прокачанный текстовый редактор</title>

 

  <!-- настраиваем служебную информацию для браузеров -->

  <meta charset="utf-8">

  <meta http-equiv="X-UA-Compatible" content="IE=edge">

  <meta name="viewport" content="width=device-width, initial-scale=1">

  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

 

  <!-- задаём CSS-стили прямо здесь же, чтобы всё было в одном файле -->

  <style type="text/css">

 

    /*задаём общие параметры для всей страницы: шрифт и отступы*/

    body{

      text-align: left;

      margin: 10;

      font-family: Courier New, Courier;

      font-size: 20px;

      background-color: lightgray;

    } 

 

    /* оформляем окно редактора */

    .editorSheet{

      min-height: 65vw;

      border: solid; 

      border-width: 0px; 

      text-align: left;

      background-color: white;

      -webkit-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      -moz-box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      box-shadow: 6px 10px 9px 0px rgba(0,0,0,0.75);

      padding: 15px;

      border-style: solid;

      border-width: 1px;

    } 

 

    /* стиль заголовка h1*/

    h1{

      font-size: 40px;

      font-family: Tahoma;

      font-weight: 900;

      padding-bottom: 30px;

    } 

 

    /* стиль заголовка h2*/

    h2{

      font-size: 25px;

      font-family: Arial;

      font-weight: 900;

      color: black;

      font-weight: 400;

      } 

 

    /* настраиваем внешний вид поля ввода*/

    input{

      display: inline-block;

      margin: 20px auto;

      border: 2px solid #eee;

      padding: 10px 20px;

      font-family: Verdana, Arial, sans-serif;

      font-size: 13px;

    } 

 

    /*как будет выглядеть каждый элемент нашего списка документов*/

    .tdItem{

      text-align: left;

      padding: 10px;

      cursor: default;

      border-radius: 7px;

      font-size: 16px;

    } 

    

    /*что произойдёт, когда мы наведём курсор на название документа в списке*/

    .tdItem:hover{

      background-color: lightblue;

    } 

 

  /*закончили со стилями*/

  </style>

 

<!-- закрываем служебную часть страницы -->

</head>

 

<!-- началось содержимое страницы -->

<body>

  <!-- началась визуальная часть -->

 

  <div class="container" >

    <div class="row">

      

      <!-- делаем заголовок -->

      <div class="col-12">

        <h1 id="h1_name">Текстовый редактор с автосохранением</h1>

      </div>

 

    </div>

  </div>



  <div class="container" >

    <div class="row">

 

      <div class="col-12 col-sm-12 col-md-4 col-lg-3 col-xl-3">

          

        <!-- делаем боковой список с названиями документов-->

          <!-- заголовок списка  -->

          <h2>Документы</h2>

          <p style="font-size: 14px">Alt + клик — удаляет документ</p>

 

          <!-- поле ввода, куда пишем название новых документов -->

          <div id="tdlApp">

            <input type="text" class="form-control" placeholder="Новый документ">

           

           <!-- создаём пока ещё пустой список -->

            <div class="tdlDiv">

 

              <ul class="List list-unstyled">

                <!-- тут появятся наши названия документов, когда мы их добавим -->

              </ul>

 

            </div>

          </div>

        <!-- закончили с оформлением списка -->

 

      </div>

 

      <!-- делаем само окно редактора, где пишем весь текст -->

      <div class="col-12 col-sm-12 col-md-8 col-lg-9 col-xl-9">

 

        <div id="editor" contenteditable="true" class="editorSheet">

        </div>

 

      </div>

 

    </div>

  </div>

 

  <!-- закончилась видимая часть -->

 

  <!-- подключаем JQuery -->

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js">

  </script>

 

  <!-- пишем скрипт, который будет постоянно сохранять наш текст -->

  <script>

 

    // заводим переменные под наши задачи

    var List = $('#tdlApp ul');

    var Mask = 'tdl_';

 

    // тут будем хранить внутренний номер документа, чтобы связать список и текст в редакторе

    var N_store;

    

    // отслеживаем каждое нажатие клавиши в редакторе и при каждом нажатии выполняем команду

    document.addEventListener('keydown', function(e) {

    

      // записываем содержимое нашего редактора в хранилище, при этом ячейка связана с текущим документом

      localStorage.setItem(N_store + 'text_in_editor', document.getElementById('editor').innerHTML);

    } );

 

    // функция, которая берёт из памяти наши документы и делает из них список

    function showTasks( ){

 

      // временно скрываем окно редактора

      document.getElementById('editor').style.display = "none";

 

      // узнаём размер хранилища

      var Storage_size = localStorage.length;

 

      // если в хранилище что-то есть…

      if (Storage_size > 0){

 

        // то берём и добавляем это в список документов 

        for (var i = 0; i < Storage_size; i++){

          var key = localStorage.key(i);

          if(key.indexOf(Mask) == 0){

 

            // запоминаем внутренний номер документа, чтобы правильно показать текст в редакторе

            N_store = key[4];

 

            // делаем содержимое хранилища элементами списка

            $('<li></li>').addClass('tdItem')

              .attr('data-itemid', key)

              .text(localStorage.getItem(key))

              .appendTo(List);

          } 

        }  

      }  

    } 

 

    // сразу вызываем эту функцию, вдруг в памяти уже остались документы с прошлого раза

    showTasks();

 

    // следим, когда пользователь напишет название нового документа в поле ввода и нажмёт Enter

    $('#tdlApp input').on('keydown',function(e){

      if(e.keyCode != 13) return;

 

      var str = e.target.value;

      e.target.value = "";

 

      // если в поле ввода было что-то написано — начинаем обрабатывать

      if(str.length > 0){

        var number_Id = 0;

 

        List.children().each(function(index, el){

          var element_Id = $(el).attr('data-itemid').slice(4);

          if(element_Id > number_Id)

            number_Id = element_Id;

        } )

        number_Id++;

        

        // отправляем новый документ сразу в память

        localStorage.setItem(Mask+number_Id,str);

 

        // готовим для него новое поле редактора

        // берём текущий внутренний номер документа

        N_store = number_Id;

 

        // отправляем в память 

        localStorage.setItem(N_store + 'text_in_editor','');

 

        // делаем окно редактора видимым и очищаем текст в нём

        document.getElementById('editor').innerHTML = '';

        document.getElementById('editor').style.display = "block";

 

        // добавляем название документа в конец списка

        $('<li></li>').addClass('tdItem')

          .attr('data-itemid', Mask+number_Id)

          .text(str).appendTo(List);

 

        // меняем заголовок редактора

        document.getElementById('h1_name').innerHTML = localStorage.getItem('tdl_' + N_store);

      } 

    } );

     

    // при клике на названии документа — делаем его активным и даём с ним работать

    $(document).on('click','.tdItem', function(e){

 

      // находим документ, по которому кликнули

      var jet = $(e.target);

 

      // если при клике был нажат Atl

      if (event.altKey) {

 

        // то убираем документ из памяти

        localStorage.removeItem(jet.attr('data-itemid'));

        localStorage.removeItem(jet.attr('data-itemid')[4] + 'text_in_editor');

 

        // очищаем и скрываем окно редактора

        document.getElementById('editor').innerHTML = '';

        document.getElementById('editor').style.display = "none";

 

        // меняем заголовок редактора

        document.getElementById('h1_name').innerHTML = 'Текстовый редактор с автосохранением';

 

        // и убираем документ из списка

        jet.remove();

 

        // выходим из функции, чтобы не обрабатывать обычный клик

        return true;

      } 

 

      // обрабатываем обычный клик — делаем документ активным

      // получаем внутренний номер документа

      N_store = jet.attr('data-itemid')[4];

      

      // делаем окно редактора видимым и заполняем его содержимым из памяти

      document.getElementById('editor').style.display = "block";

      document.getElementById('editor').innerHTML = localStorage.getItem(N_store + 'text_in_editor');

 

      // меняем заголовок редактора

      document.getElementById('h1_name').innerHTML = localStorage.getItem('tdl_' + N_store);

       

    } )

 

  // закончился скрипт

  </script>

 

<!-- закончилось содержимое страницы -->

</body>

 

<!-- конец всего HTML-документа -->

</html>


Ско­пи­ро­вать код
Код ско­пи­ро­ван
Ещё по теме