ea20d86d1642c1ac25ff925659a41b8621922f29
   1var mainlist;
   2var rmspan = ["<span class='remove' id='delete-", "'>–</span>"]
   3var tick = "✔";
   4var removebg = "#bf616a";
   5var hovergrn = "#a3be8c";
   6var hoverbg = "#434c5e";
   7var hoverbg2 = "#848ead";
   8document.addEventListener("DOMContentLoaded", function() {
   9  chrome.storage.sync.get(
  10    {"lists": [
  11      ["General",
  12        ["Github", "https://github.com"],
  13        ["Wikipedia", "https://en.wikipedia.org"],
  14        ["Gmail", "https://mail.google.com"]
  15      ],
  16      ["Productivity",
  17        ["Desmos", "https://www.desmos.com/calculator"],
  18        ["Wolfram", "https://wolframalpha.com"],
  19        ["Hacker News", "https://news.ycombinator.com"]
  20      ],
  21      ["Social",
  22        ["Reddit", "https://www.reddit.com"],
  23        ["YouTube", "https://youtube.com"],
  24        ["Instagram", "https://instagram.com"]
  25      ]
  26    ]
  27},
  28    userListsCallback);
  29});
  30
  31function columnToArray(list) {
  32  var l = [];
  33  var elem = list.getElementsByClassName("item");
  34  for (var i = 0; i < elem.length; ++i) {
  35    l[i] = [elem[i].innerText, elem[i].getAttribute("href")];
  36  }
  37  return l;
  38}
  39
  40function listToArray(list) {
  41  var l = [];
  42      console.log("looking at list:");
  43      console.log(list);
  44  if (editMode == true) {
  45    l[0] = list.getElementsByClassName('title')[0].getElementsByTagName("input")[0].value;
  46  }
  47  else {
  48    l[0] = list.getElementsByClassName('title')[0].getElementsByTagName("p")[0].textContent;
  49  }
  50  var elem = list.getElementsByTagName("li");
  51  for (var i = 0; i < elem.length; ++i) {
  52    if (elem[i].class == "new") {
  53      continue;
  54    }
  55    else {
  56      l[i+1] = [elem[i].getElementsByTagName("a")[0].innerText, elem[i].getElementsByTagName("a")[0].getAttribute("href")];
  57    }
  58  }
  59  return l;
  60}
  61
  62var userListsCallback = function(lists) {
  63  mainlist = []
  64  for (let x of lists['lists']) {
  65    mainlist.push(x[0]);
  66  }
  67  for(var i=0;i<lists["lists"].length;i++) {
  68    document.getElementById('edit').addEventListener('click', edit, false);
  69    document.getElementById('addcol').addEventListener('click', addCol, false);
  70    var ul = document.createElement("ul");
  71    ul.setAttribute("id", mainlist[i]);
  72    ul.setAttribute('draggable', 'false'); // Draggable attribute must be set on mousedown event, otherwise any cursor movement causes dragstart()
  73    document.getElementById("links").appendChild(ul);
  74
  75    var grip = document.createElement("span");
  76    grip.setAttribute("class", "grip");
  77    grip.addEventListener('mousedown', function() {
  78      console.log("Drag started");
  79      uls = document.getElementsByTagName("ul");
  80      for (let ul of uls) {
  81        ul.setAttribute("draggable", "true");
  82        ul.addEventListener('dragstart', dragStart, false);
  83        ul.addEventListener('dragenter', dragEnter, false);
  84        ul.addEventListener('dragover', dragOver, false);
  85        ul.addEventListener('dragleave', dragLeave, false);
  86        ul.addEventListener('drop', drop, false);
  87      }
  88    });
  89
  90    grip.addEventListener('mouseup', function() {
  91      console.log("Drag ended");
  92      uls = document.getElementsByTagName("ul");
  93      for (let ul of uls) {
  94        ul.setAttribute("draggable", "false");
  95        ul.removeEventListener('dragstart');
  96        ul.removeEventListener('dragenter');
  97        ul.removeEventListener('dragover');
  98        ul.removeEventListener('dragleave');
  99        ul.removeEventListener('drop');
 100      }
 101    });
 102
 103    var title = document.createElement("div");
 104    title.setAttribute("class", "title");
 105    ul.appendChild(grip)
 106    ul.appendChild(title);
 107
 108    var p = document.createElement("p");
 109    p.innerText = mainlist[i];
 110    title.appendChild(p);
 111
 112    title.insertAdjacentHTML("beforeend", "<span class='add' id='add-"+mainlist[i]+"'>+</span>");
 113
 114    var list = lists["lists"][i];
 115    for(var j=1;j<lists["lists"][i].length;j++) {
 116      var li = document.createElement("li");
 117      li.setAttribute("id", mainlist[i]+"-"+j);
 118      var siteurl = list[j][1];
 119      var nme = list[j][0];
 120      var img = document.createElement("img");
 121      img.className = "icon";
 122      img.src = "https://www.google.com/s2/favicons?domain="+siteurl+"";
 123      li.insertAdjacentHTML("beforeend", "<a class='item' href="+siteurl+"><img src="+img.src+" alt="+extractDomain(siteurl,1)+"/> "+nme+"</a>");
 124      li.insertAdjacentHTML("beforeend", rmspan[0] + j + "-" + mainlist[i] + rmspan[1]);
 125      ul.appendChild(li);
 126    }
 127
 128    new Sortable(ul, {
 129      group: "userlists",
 130      animation: 150,
 131      onUpdate: function (evt) {
 132        save();
 133      }
 134    });
 135  }
 136
 137  menu();
 138
 139};
 140
 141function dragStart(e) {
 142  dragSrcEl = this;
 143  e.dataTransfer.effectAllowed = 'move';
 144  e.dataTransfer.setData('text/html', this.innerHTML);
 145}
 146
 147function dragOver(e) {
 148  if (e.preventDefault) {
 149    e.preventDefault();
 150  }
 151  e.dataTransfer.dropEffect = 'move';
 152  return false;
 153}
 154
 155function dragEnter(e) {
 156  this.classList.add('over');
 157}
 158
 159function dragLeave(e) {
 160  this.classList.remove('over');
 161}
 162
 163function drop(e) {
 164  if (e.stopPropagation); {
 165    e.stopPropagation();
 166  }
 167  if (dragSrcEl != this) {
 168    dragSrcEl.innerHTML = this.innerHTML;
 169    this.innerHTML = e.dataTransfer.getData('text/html');
 170    save();
 171    menu();
 172  }
 173  return false;
 174}
 175
 176var dragSrcEl = null;
 177
 178document.onkeyup=function(e){
 179  var e = e || window.event; // for IE to cover IEs window event-object
 180  fields = document.getElementsByClassName("new");
 181  if(e.which == 27 && fields != null) {
 182    fields[fields.length-1].remove();
 183    return false;
 184  }
 185  if(e.which == 13 && fields.length > 0) {
 186    fields[fields.length-1].getElementsByClassName("save")[0].click();
 187    return false;
 188  }
 189}
 190
 191var editMode = false;
 192
 193function edit() {
 194  if (editMode == true) {
 195    console.log("Exited edit mode");
 196    closeEdit(this);
 197    return 0;
 198  }
 199  console.log("Entered edit mode");
 200  this.style.background = hovergrn;
 201  this.innerText = tick;
 202  addbtn = document.getElementById("addcol");
 203  addbtn.style.display = "flex";
 204  var cols = document.getElementsByTagName("ul");
 205  for (let col of cols) {
 206    col.style.bottom = "26px";
 207    title = col.getElementsByClassName("title")[0];
 208    rmbutton = document.createElement("span"); 
 209    rmbutton.setAttribute("class", "rmcol");
 210    rmbutton.setAttribute("id", "rmcol-"+col.id);
 211    rmbutton.innerText = "-";
 212    rmbutton.addEventListener('click', function(event){
 213      console.log("Deleting column " + this.parentNode.parentNode);
 214      this.parentNode.parentNode.remove();
 215      var index = mainlist.indexOf(this.parentNode.parentNode.id);
 216      console.log("Found deleted node " + this.parentNode.parentNode.id + " at index " + index);
 217      if (index > -1) {
 218        mainlist.splice(index, 1);
 219      }
 220      save();
 221    });
 222    title.appendChild(rmbutton);
 223    title.getElementsByClassName("add")[0].style.display = "flex";
 224    titlep = title.getElementsByTagName("p")[0];
 225    editTitle = document.createElement("input");
 226    titlep.insertAdjacentHTML("afterend", "<input type='text' class='colname' placeholder='category' value='" + titlep.innerText + "'>");
 227    titlep.remove();
 228    col.getElementsByClassName("grip")[0].style.display = "inline-block";
 229  }
 230  editMode = true;
 231}
 232
 233function closeEdit(editbtn) {
 234  editMode = false;
 235  editbtn.style.background = "";
 236  editbtn.innerText = "e";
 237  addbtn = document.getElementById("addcol");
 238  addbtn.style.display = "none";
 239  var cols = document.getElementsByTagName("ul");
 240  for (let col of cols) {
 241    col.style.bottom = "0";
 242    rmbutton = col.getElementsByClassName("title")[0].getElementsByClassName("rmcol")[0];
 243    rmbutton.remove();
 244    title = col.getElementsByClassName("title")[0];
 245    title.getElementsByClassName("add")[0].style.display = "";
 246    editTitle = title.getElementsByClassName("colname")[0];
 247    titlep = document.createElement("p");
 248    titlep.innerText = editTitle.value;
 249    editTitle.remove();
 250    title.appendChild(titlep);
 251    col.getElementsByClassName("grip")[0].style.display = "none";
 252  }
 253  save();
 254}
 255
 256function addCol() {
 257  var ul = document.createElement("ul");
 258  ul.setAttribute("id", "new");
 259  ul.setAttribute('draggable', 'true');
 260  ul.addEventListener('dragstart', dragStart, false);
 261  ul.addEventListener('dragenter', dragEnter, false);
 262  ul.addEventListener('dragover', dragOver, false);
 263  ul.addEventListener('dragleave', dragLeave, false);
 264  ul.addEventListener('drop', drop, false);
 265  document.getElementById("links").appendChild(ul);
 266
 267  var grip = document.createElement("span");
 268  grip.setAttribute("class", "grip");
 269
 270  var title = document.createElement("div");
 271  title.setAttribute("class", "title");
 272  title.appendChild(grip)
 273  ul.appendChild(title);
 274
 275  var p = document.createElement("p");
 276  p.innerText = "new";
 277  title.appendChild(p);
 278
 279  title.insertAdjacentHTML("beforeend", "<span class='add' id='add-new'>+</span>");
 280
 281  rmbutton = document.createElement("span"); 
 282  rmbutton.setAttribute("class", "rmcol");
 283  rmbutton.setAttribute("id", "rmcol-new");
 284  rmbutton.innerText = "-";
 285  rmbutton.addEventListener('click', function(event){
 286    console.log("Deleting column " + this.parentNode.parentNode);
 287    this.parentNode.parentNode.remove();
 288    var index = mainlist.indexOf(this.parentNode.parentNode.id);
 289    console.log("Found deleted node " + this.parentNode.parentNode.id + " at index " + index);
 290    if (index > -1) {
 291      mainlist.splice(index, 1);
 292    }
 293    save();
 294  });
 295  title.appendChild(rmbutton);
 296  title.getElementsByClassName("add")[0].style.display = "flex";
 297  titlep = title.getElementsByTagName("p")[0];
 298  editTitle = document.createElement("input");
 299  titlep.insertAdjacentHTML("afterend", "<input type='text' class='colname' placeholder='category'>");
 300  titlep.remove();
 301  
 302  mainlist.push(["new"]);
 303  save();
 304  listen(title.getElementsByClassName("add")[0]);
 305}
 306
 307function listen(li) {
 308  li.addEventListener('click', function(event){
 309    var r = event.target.id.split("-");
 310    if (r[0] == "delete") {
 311      var el = document.getElementById(r[2]+"-"+r[1]);
 312      el.outerHTML = "";
 313      delete el;
 314      save();
 315    } else {
 316      addItem(r, li);
 317    }
 318  }, true);
 319}
 320
 321function addItem(caller, li) {
 322      if (ul == null) {
 323        var ul = li.parentNode.parentNode;
 324        var id = ul.id;
 325      }
 326      else {
 327        var ul = document.getElementById(caller[1]);
 328        var id = caller[1];
 329      }
 330      
 331      if (document.querySelectorAll("#"+id+" .new").length > 0) {
 332        fields = document.querySelector("#"+id+" .new .name");
 333        fields.focus(); 
 334        return false;
 335      }
 336      var li = document.createElement("li");
 337      li.setAttribute("class", "new");
 338      li.insertAdjacentHTML("beforeend", "<span class='save' tabindex='3' id='input-"+columnToArray(li).length.toString()+"'>"+tick+"</span><input type='text' class='name' value='' placeholder='name' tabindex='1'><br /><input type='url' spellcheck=false class='url' value='' placeholder='url' tabindex='2' id='form-"+columnToArray(li).length.toString()+"'>");
 339      ul.appendChild(li);
 340      var span = document.getElementById("input-"+columnToArray(li).length.toString());
 341      var form = document.getElementById("form-"+columnToArray(li).length.toString());
 342      span.addEventListener('click', function(event){
 343        console.log("Adding item to:");
 344        console.log(this);
 345        var li = document.getElementsByClassName("new")[0]
 346        var ul = li.parentNode;
 347        if (li.getElementsByClassName("name")[0].value != "" && li.getElementsByClassName("url")[0].value != "" && li.getElementsByClassName("url")[0].validity.typeMismatch== false) {
 348          var newli = document.createElement("li");
 349          newli.setAttribute("id",caller[1]+"-"+columnToArray(ul).length.toString());
 350          var siteurl = addhttp(li.getElementsByClassName("url")[0].value);
 351          var nme = li.getElementsByClassName("name")[0].value;
 352          li.remove()
 353          delete li;
 354
 355          newli.insertAdjacentHTML("beforeend", "<a href="+siteurl+">"+nme+"</a>");
 356          newli.insertAdjacentHTML("beforeend", rmspan[0]+columnToArray(ul).length.toString()+"-"+caller[1]+rmspan[1]);
 357          document.getElementById(id).appendChild(newli);
 358          save();
 359          listen(newli);
 360        }
 361        else {
 362          if (li.getElementsByClassName("name")[0].value == "" && li.getElementsByClassName("url")[0].value == "") {
 363            console.log("No data supplied, deleting form");
 364            this.parentNode.remove();
 365          }
 366          else {
 367            console.log("Missing data, press Esc to delete form");
 368          }
 369        }
 370      });
 371      span.onmouseover = function() {
 372        nme = document.getElementsByClassName("name")[0];
 373        url = document.getElementsByClassName("url")[0];
 374        if (nme.value === ''  || url.value === '' || url.validity.typeMismatch == true) {
 375          this.style.background = removebg;
 376        }
 377        else {
 378          this.style.background = hovergrn; 
 379        }
 380      };
 381      span.onmouseout = function() {
 382        this.style.background = hoverbg2;
 383      };
 384      menu(); // TODO fix bug where form save button loses its eventlistener after generating form for another column twice
 385      fields = document.querySelector("#"+id+" .new .name");
 386      fields.focus(); 
 387
 388}
 389
 390function menu() {
 391  // Update event listeners for all items, their remove buttons, and the add button for each column
 392  var allUserLi = document.querySelectorAll('.remove, .add');
 393
 394  allUserLi.forEach(function(li, p_index){
 395    listen(li);
 396  });
 397}
 398
 399function save(l) {
 400  console.log(mainlist);
 401  var set = l || JSON.parse(JSON.stringify(mainlist));
 402  d = []
 403  d = set;
 404  console.log("Saving settings");
 405  for (var i = 0; i < set.length; ++i) {
 406    d[i] = listToArray(document.getElementById(set[i]));
 407  }
 408  chrome.storage.sync.set( {"lists": d} );
 409}