<repo_name>lukasz-m-b/quick-lookup<file_sep>/ajax.php
<?php
require_once('WordEntry.php');

session_start();

// ini_set('display_errors', 1); 
// error_reporting(E_ALL ^ E_STRICT);

list($command, $value) = each(json_decode(file_get_contents('php://input'), true)); 

$commands_white_list = ['fetch', 'prepare_download'];  

if (in_array($command, $commands_white_list)) {
  echo json_encode($command($value));
} else {
  echo '{"error":"illegal request to server"}'; 
}


function db() {
  return new PDO($_SESSION['pdo_data'][0], $_SESSION['pdo_data'][1], $_SESSION['pdo_data'][2]);
}


function fetch($word) {
  $from_db = fetch_word_from_db($word);
  if ($from_db !== false) {
    return ['response' => $from_db->HTML()];
  }
  
  $from_online = fetch_word_online($word);
  if ($from_online !== false) {
    return ['response' => $from_online->HTML()];
  }
  
  return ['error' => 'not found'];
}


function fetch_word_online($word) {
  $dom = new DOMDocument();
 @$dom->loadHTMLFile("http://pl.bab.la/slownik/angielski-polski/$word");
  $sections = $dom->getElementsByTagName('section');

  $section = null;

  for ($i = 0; $i < $sections->length; $i++) {
    if (strpos($sections->item($i)->nodeValue, 'tłumaczenie polskie') !== false) {
      $section = $sections->item($i);
      break;
    }
  }
  
  if ($section === null) {
    return false;
  }
  
  $a_in_section = $section->getElementsByTagName('a');

  $a_words = [];
  
  for ($i = 0; $i < $a_in_section->length; $i++) {
    $a = $a_in_section->item($i);
    if ($a->hasAttribute('href') && strpos($a->getAttribute('href'), 'babSpeakIt') !== false) {
      $a_words[] = $a->nextSibling->nextSibling->nodeValue;
    }
  }
  
  if (empty($a_words)) {
    return false;
  }
  
  $word_entry = new WordEntry($a_words);
  
  $db = db();
  $insert = $db->prepare("INSERT INTO words VALUES (NULL, ?, ?);"); 
  $insert->execute([$word, $word_entry->JSON()]);
  
  return $word_entry;
}


function fetch_word_from_db($word) {
  $db = db();
  
  $get = $db->prepare("SELECT word_entry FROM words WHERE queried_word = ? LIMIT 1");
  $get->execute([$word]);
  
  $fetched = $get->fetchAll(PDO::FETCH_ASSOC);
  if (empty($fetched)) {
    return false;
  }
  
  return new WordEntry(json_decode($fetched[0]['word_entry']));
}


function prepare_download($html) {
  $_SESSION['html'] = $html;
  return ['response' => 'ok'];
}

?>
<file_sep>/WordEntry.php
<?php 

class WordEntry {
    
  private $meanings;
  
  public function __construct($data) {
    if (is_array($data)) {  // from html
      $this->meanings = []; 
      for($i = 0; $i < count($data); $i += 2) {
        $en = $data[$i];
        $pl = $data[$i + 1];
        if (array_key_exists($en, $this->meanings)) {
          $this->meanings[$en][] = $pl;
        } else {
          $this->meanings[$en] = [$pl];
        }
      }
    } else {  // from json  
      $this->meanings = (array) $data;
    }
  }
  
  
  public function __debugInfo() {
    return $this->meanings;
  }
  
  
  public function HTML() {
    $html = '';
    
    foreach($this->meanings as $en => $pl) {
      $html .= '<p><a href="javascript:;" class="word_en is_selected">' . $en . '</a>: &nbsp; ';
      foreach ($pl as $word_pl) {
        $html .= '<a href="javascript:;" class="word_pl is_selected">' . $word_pl . '</a> &nbsp; ';
      }
      $html .= '</p>';
    }
    
    return $html;
  }
  
  
  public function JSON() {
    return json_encode($this->meanings);
  }
}


?>
<file_sep>/README.md
# quick-lookup

##### (this is an early experimental version, take a look version 2.0)

A PHP/jQuery application for speakers of Polish to facilitate reading English texts and learning new vocabulary. It still has some rough edges and there is a lot of functionality to add. 

http://lukaszb.byethost15.com/quick_lookup/ 
<file_sep>/download.php
<?php 

header('content-type: text/html');
header('content-disposition: attachment; filename="words_' 
  . (new DateTime())->format('Y-m-d') . '".html'
);
session_start();

if (!isset($_SESSION['html'])) {
  exit();
}

?>
<html>
<meta charset="UTF-8">
<style>
body {
  font-family: Arial, Helvetica, sans-serif;
  font-size: medium;
}

p.note_sentence {
  font-style: italic;
}

span.word_emphasize {
  font-weight: bold;
  color: navy;
}
</style>
<?php

echo str_replace('<button class="remove_note">usuń notatkę</button>', '<hr>', $_SESSION['html']);
echo '</html>'; 
exit();

?>
<file_sep>/index.php
<?php 
// ini_set('display_errors', 1); 
// error_reporting(E_ALL ^ E_STRICT);
session_start(); 
?>

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="quick-lookup.css" type="text/css">
    <link rel="shortcut icon" href="green.png" type="image/png">
    <title>quick lookup</title>
  </head>
  
  <body>
    
    <div id="top_title"><h1>quick lookup</h1></div>
    
    <div id="lookup">
      <div class="hint" id="lookup_hint"></div>
      <table>
        <tr>
          <td id="lookup_text" style="width: 50%; text-align: justify;">
            <textarea id="lookup_text_textarea" cols="100" rows="20">
"He's not coming back out, I tell you!" stated a pimply-faced man, shaking his head with finality. "It's been an hour and a quarter since he went in. He's done for."

The townsfolk, huddled together in the midst of the ruins and rubble, watched the gaping black hole of the entrance to the tunnel in silence. A fat man dressed in a yellow smock shifted slightly from one foot to the other, cleared his throat and pulled his wrinkled cap from his head.

"We have to wait a bit longer," he said as he wiped the sweat from his sparse eyebrows.

"Why wait?" snorted pimply, "There in the caves lurks a basilisk, or have you forgotten, burgrave? Anyone goes down there, that's the end of them. Have you forgotten how many have died down there already? What are we waiting for?"

"This was the agreement, wasn't it?" murmured the fat man uncertainly.

"An agreement you made with a living man, burgrave" said the pimply-faced man's companion, a giant of a man in a leather butcher's apron. "He is now dead, as surely as the sun shines in the sky. It was plain from the beginning that he was headed towards death, like all the others before him. He didn't even take a mirror with him, only a sword - and everybody knows you need a mirror in order to kill a basilisk."
            </textarea><br>
            <button id="lookup_text_analyze">analizuj</button>
          </td>
          <td id="lookup_glosses">
            
          </td>
        </tr>
      </table>
    </div>
    
    <hr> 
    
    <div id="notes">
      
    </div>
    
    <div style="text-align: center;">
      <button id="download">zapisz notatki do pliku</button>
    </div>
    
    
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
    <script src="quick-lookup.js"></script>
  </body>
</html>

<?php

$_SESSION['pdo_data'] = json_decode(file_get_contents('pdo.data'), true);

?>  
<file_sep>/quick-lookup.js


var debugging = false; 
//debugging = true;

var word_html_cache = {};
var last_sentence_clicked = ''; 


$('body').on('click', '#lookup_text_analyze', function() {
  
  analyze_text();
    
}).on('click', '#lookup_new', function() {
  
  $('td#lookup_text').html('<textarea id="lookup_text_textarea" cols="100" rows="15">' +
          '</textarea><br>' +
          '<button id="lookup_text_analyze">analyze</button>');
          
  $('td#lookup_glosses').empty();
  
}).on('click', 'a.word', function() {
  
  var searched = $(this).text();
  
  last_sentence_clicked = $(this).parent().text().replace(
    new RegExp(' ' + searched + ' ', 'g'), 
    function(x) {return ' <span class="word_emphasize">' + x + '</span> ';}
  ).replace(
    /\s+([\.\?\,\!])/g, 
    function(m) {return m[1];}
  );
  
  if (searched in word_html_cache) {
    $('#lookup_glosses').fadeOut(200, function() {
      $('#lookup_glosses').html(word_html_cache[searched]).append(
      '<button id="make_note">zapisz notatkę</button>'
    );}).fadeIn();
    return;
  }
  
  ajax(
  {fetch: searched}, 
  function(html) {
    word_html_cache[searched] = html.response;
    $('#lookup_glosses').fadeOut(200, function() {
      $('#lookup_glosses').html(html.response).append(
      '<button id="make_note">zapisz notatkę</button>'
    );}).fadeIn();
  }, 
  function(error) {
    if (error.error === 'not found') {
      last_sentence_clicked = '';
      display_error('nieznane słowo');
    }
  });
  
}).on('click', 'a.word_pl', function() {
  
  $(this).toggleClass('is_selected');
  if ($(this).hasClass('is_selected')) {
    $('.word_en', $(this).parent()).first().addClass('is_selected');
  }
  
}).on('click', 'a.word_en', function() {
  
  var word_en_is_selected = $(this).hasClass('is_selected');
  $(this).parent().children().each(
    word_en_is_selected
    ? function(_, a) {$(a).removeClass('is_selected');}
    : function(_, a) {$(a).addClass('is_selected');}
  );

}).on('click', '#make_note', function() {
  
  if (last_sentence_clicked === '') {
    return;
  }
  
  var note = '<div class="note"><p class="note_sentence">' + last_sentence_clicked + '</p>';
  var words_added = false;
  
  $('td#lookup_glosses p').each(function(_, p) {
    var glosses = $(p).children();
    if (glosses.first().hasClass('is_selected')) {
      var note_gloss = '<p><span class="word_emphasize">' + glosses.first().text() + '</span>: &nbsp; ';
      glosses.slice(1).each(function(_, a) {
        if ($(a).hasClass('is_selected')) {
          note_gloss += $(a).text() + ' &nbsp; ';
        }
      });
      note += note_gloss + '</p>';
      words_added = true;
    }
  });
  
  if (words_added) {
    $('#notes').append(note + '<button class="remove_note">usuń notatkę</button><br><br></div>');
  }
  
}).on('click', '.remove_note', function() {
  
  $(this).parent().slideUp(200, function() {$(this).remove();});
  
}).on('click', '#download', function() {
  
  if ($('#notes').children().length > 0) {
    ajax({prepare_download: $('#notes').html()}, function() {
      window.location = 'download.php'; 
    });
  }
  
}); 


// ----- // 


function ajax(to_send, callback, error_callback) { 
  $.ajax({
    url: 'ajax.php',
    method: 'post',
    data: JSON.stringify(to_send),
    processData: false,
    contentType: 'application/json; charset=UTF-8',
    success: function(received) {
      
      if (debugging) {
        console.log(received);
        return;
      }
   
      var response = JSON.parse(received);
      
      if ('error' in response) {
        if (error_callback) {
          error_callback(response);
        } else {
          display_error('ERROR\n' + response.error);
        }
      } else if (callback) {
        callback(response);
      }
      
    },
    error: function() {
      display_error('błąd połączenia z serwerem');
    }
  });
}


function display_error(msg) {
  alert(msg);
}


// ----- //


$('#lookup_hint').attr('data-hint',
  'Ta strona pomoże Ci szybko sprawdzać nieznane słowa w angielskich tekstach. <ul>' +
  '<li>wklej dowolny angielski tekst i kliknij <i>analizuj</i></li>'+
  '<li>gdy natrafisz na nieznane słowo, kliknij je, by sprawdzić znaczenie w słowniku</li>' +
  '<li>klikając <i>zapisz notatkę</i>, możesz zapisać nowe słowo, by go nie zapomnieć</li>' +
  '<li>słownik podaje wszystkie znaczenia słowa - jeśli niektóre uważasz za niepotrzebne ' + 
  'lub niepasujące do zdania, możesz je łatwo usunąć</li></ul>');


function show_hint(div) {
  div.html(div.attr('data-hint') + ' ').append(
    $(' <a class="got_it" href="javascript:;">jasne</a>').click(function() {
      hide_hint($(this).parent());
    }));
}


function hide_hint(div) {
  div.html($(' <a class="got_it" href="javascript:;">co&nbsp;to&nbsp;jest?</a>').click(function() {
    show_hint($(this).parent());
  }));
}


$('div.hint').each(function() {
  hide_hint($(this));
}); 


// ----- //


function analyze_text() {
  var html = '<span class="sentence">' + 
  $('#lookup_text_textarea').val().replace(/[\.\?\,\"\'\/\!\&\(\)\[\]\<\>\n\—\”\“\’]/g, function(m) {
    return ' ' + m + ' ';
  }).split(/[\t ]+/).map(function(x) {
    if ('?,"\'/!&()[]<>—”“’'.indexOf(x) !== -1) {
      return '<span class="punc">' + $('<div />').text(x).html() + '</span>';
    } else if (x === '.') {
      return '</span>.<span class="sentence">';
    } else if (x === '?') {
      return '</span>?<span class="sentence">';
    } else if (x === '!') {
      return '</span>!<span class="sentence">';
    } else if (x === '\n' || x === '\r') {
      return '<br>';
    } else {
      return ' <a class="word">' + $('<div />').text(x).html() + '</a> ';
    }
  }).join('') + '</span>';
  
  $('td#lookup_text').html(
    '<div style="height: 500px; overflow-y: scroll; padding: 10px; margin: 5px">' + html + '</div>'
  ).append('<br><button id="lookup_new">nowy tekst</button>');
}
