Преобразовать текстовый список с отступом в список HTML (jQuery)

0

Я пытаюсь создать сценарий jQuery, который преобразует отступом текстовый список произвольной длины и глубины в правильно отформатированный список HTML. Списки, на которых я буду запускать этот скрипт, являются простыми древовидными структурами для каталогов. Внутри древовидных структур папки обозначаются точкой с запятой, следующей за именем папки (а файлы не имеют окончательной пунктуации). Учитывая это, я хотел бы прикрепить к строке строки <span class="folder"></span> или <span class="file"></span>.

Я обнаружил, что довольно легко сгенерировать большую часть структуры, но я не могу получить рекурсию (которая, как я подозреваю, потребуется), чтобы убедиться, что теги правильно вложены. Страница, на которой это будет реализована, будет включать самую последнюю версию Bootstrap (т.е. 3.0.3), поэтому не стесняйтесь использовать любую ее функциональность. У меня около двух десятков (как правило, прерывистых) фрагментов кода, которые я пробовал, или которые я сейчас пытаюсь настроить для получения желаемого результата. Вместо публикации массы (вероятно, бесполезного) кода, я создал JSFiddle с базовой формой, которая будет использоваться для ввода/вывода, бит jQuery, список примеров и загруженные внешние библиотеки.

Любая помощь или предложения будут очень благодарны.

  • 0
    Прошу также почтовый индекс, который вы пытались, который дал вам большую часть пути
  • 0
    Вы не можете получить свои данные в JSON? Используя те же вложенные свойства в json, нетрудно рекурсивно зацикливаться на дочерних элементах ... jsfiddle.net/charlietfl/pCsZ3
Показать ещё 3 комментария
Теги:
html-lists

3 ответа

2
Лучший ответ

Попробуй это. Я скопировал его на свою скрипку и, похоже, сработал.

var indentedToHtmlList = function indentedToHtmlList (text, indentChar, folderChar, listType, showIcons) {
  indentChar = indentChar || '\t';
  folderChar = folderChar || ':';
  listType = listType || 'ul';
  showIcons = !!showIcons;

  var lastDepth,
      lines = text.split(/\r?\n/),
      output = '<' + listType + '>\n',
      depthCounter = new RegExp('^(' + indentChar + '*)(.*)');

  for (var i = 0; i < lines.length; i++) {
    var splitted = lines[i].match(depthCounter),
        indentStr = splitted[1],
        fileName = splitted[2],
        currentDepth = (indentStr === undefined) ? 0 : (indentStr.length / indentChar.length),
        isFolder = (fileName.charAt(fileName.length - 1) === folderChar);

    if (isFolder) {
      fileName = fileName.substring(0, fileName.length -1);
    }

    if (lastDepth === currentDepth) {
      output += '</li>\n';
    } else if (lastDepth > currentDepth) {
      while (lastDepth > currentDepth) {
        output += '</li>\n</' + listType + '>\n</li>\n';
        lastDepth--;
      }
    } else if (lastDepth < currentDepth) {
      output += '\n<' + listType + '>\n';
    }

    output += '<li>';
    if (showIcons) {
      output += '<span class=" glyphicon glyphicon-' +
      (isFolder ? 'folder-open' : 'file') +
      '"></span> ';
    }
    output += fileName;

    lastDepth = currentDepth;
  }

  while (lastDepth >= 0) {
    output += '\n</li>\n</' + listType + '>';
    lastDepth--;
  }

  return output;
};
  • 0
    Хотя я подозреваю, что проблема связана с ошибкой конечного пользователя, я не смог заставить этот скрипт работать с моим JSFiddle. Не могли бы вы взглянуть на текущую версию: jsfiddle.net/Zyniker/3ZuEK/5 и, возможно, разложить ее, чтобы ваш скрипт работал? Ваш скрипт кажется более элегантным решением, чем (несколько сомнительное) решение CoffeeScript, которое я разместил выше .
  • 2
    Да, смотрите здесь: jsfiddle.net/bFq7H/1
Показать ещё 13 комментариев
1

Вы можете использовать пробелы и классы для обозначения файлов и папок, но вам следует рассмотреть использование элементов ul и li, которые они были созданы для этого.

Весь список должен быть заключен в элемент ul. Каждая запись в списке верхнего уровня должна создавать элемент li внутри основного элемента. Если элемент является папкой, тогда он должен также добавить другую строку ul. Здесь вам понадобится рекурсия, чтобы обеспечить правильное вложение.

Однако, если вы намереваетесь использовать отступы (без отступов с отступом), вкладка и синтаксический анализ - это проблема сама по себе, которую я не решаю в этом ответе. Для этого примера я просто притворяюсь, что у вас есть волшебная функция, которая превращает текст в анализируемый список, называемый MyList, и что файлы, принадлежащие к папке, находятся за первой точкой с запятой каждого элемента списка.

var turnTextIntoList=function(AText) {
    //magic stuff;
    return SomeList;
};

var populateList=function(AList) {
    var mainelement=jQuery('<ul></ul>');
    for(element in AList) { 
        var the_li=jQuery('<li></li>');
        if(element.indexOf(';')!=-1) {
             the_li.append('<span class="file">'+element+'</span>');
        } else {
              var thefolder=element.split(';')
              the_li.append('<span class="folder">'+thefolder[0]+'</span>');
              the_li.append(populateList(turnTextIntoList(thefolder[1])));
        } 
        mainelement.append(the_li);
    }
    return mainelement;
};

var MyList=turnTextIntoList(MyText);
jQuery('#targetdiv').append(populateList(MyList));

Смотрите, часть рекурсии - это то место, где вы делаете

the_li.append(populateList(turnTextIntoList(thefolder[1])));

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

  • 0
    На самом деле я собираюсь использовать элементы ul и li , ведь span просто предназначен для прикрепления глифов. Я вижу, ваш сценарий действительно добавляет span ; кстати, это именно то, что я и хотел. То, что я пытаюсь заставить скрипт сделать, и что, я подозреваю, твое почти делает, это правильно преобразовать текст с отступом в список HTML с соответствующей разметкой. По сути, именно то, что делает этот скрипт: codepen.io/jamiely/pen/AbEjd , но желательно с jQuery, а не с CoffeeScript (и, да, я попытался преобразовать этот скрипт, используя инструмент CoffeeScript на их веб-сайте, и это не удалось).
0

Похоже, кто-то уже создал скрипт, который делает это. К сожалению, этот скрипт находится в CoffeeScript, а не в JavaScript. Однако есть ряд онлайн-конвертеров, которые будут конвертировать из CoffeeScript в JavaScript. Благодаря @charlietfl, который предоставил ссылку на рабочий преобразователь, см. Выше.

Вот преобразованный рабочий код:

var bind, blank, convert, index, li, lineToMap, linesToMaps, parse, parseTuples, ptAccum, runConvert, tabCount, ul, ulEnd;

convert = function(text) {
  return parse(text.split('\n'));
};

li = function(t) {
  var html;
  html = "<li>" + t['line'] + "</li>";
  ptAccum.push(html);
  return html;
};

ul = function(t) {
  return ptAccum.push("<ul>" + (li(t)));
};

ulEnd = function() {
  return ptAccum.push("</ul>");
};

ptAccum = [];

index = 0;

parse = function(lines) {
  var ts;
  ts = linesToMaps(lines);
  ptAccum = ["<ul>"];
  index = 0;
  parseTuples(ts, 0);
  ulEnd();
  return ptAccum.join("\n");
};

parseTuples = function(tuples, level) {
  var stop, _p, _results;
  stop = false;
  _p = function() {
    var curLevel, t;
    t = tuples[index];
    curLevel = t['level'];
    index++;
    if (curLevel === level) {
      return li(t);
    } else if (curLevel < level) {
      index--;
      return stop = true;
    } else {
      ul(t);
      parseTuples(tuples, level + 1);
      return ulEnd();
    }
  };
  _results = [];
  while (!stop && index < tuples.length) {
    _results.push(_p());
  }
  return _results;
};

tabCount = function(line) {
  var c, count, i, inc, isTab, tc;
  tc = 0;
  c = '\t';
  count = 0;
  if (line) {
    count = line.length;
  }
  i = 0;
  isTab = function() {
    return c === '\t';
  };
  inc = function() {
    c = line.charAt(i);
    if (isTab()) {
      tc++;
    }
    return i++;
  };
  while (isTab() && i < count) {
    inc();
  }
  return tc;
};

lineToMap = function(line) {
  return {
    line: line,
    level: tabCount(line)
  };
};

blank = function(line) {
  return !line || line.length === 0 || line.match(/^ *$/);
};

linesToMaps = function(lines) {
  var line, _i, _len, _results;
  _results = [];
  for (_i = 0, _len = lines.length; _i < _len; _i++) {
    line = lines[_i];
    if (!(blank(line))) {
      _results.push(lineToMap(line));
    }
  }
  return _results;
};

runConvert = function() {
  var result;
  result = convert($('#textarea-plain-text').val());
  $('#textarea-converted-text').val(result);
  return $('#div-converted-text').html(result);
};

bind = function() {
  return $('#list-conversion-button').click(runConvert);
};

$(bind);

JSFiddle

  • 0
    Однако есть две оставшиеся проблемы: 1. этот код не устраняет все отступы в исходном текстовом списке (и, если я не ошибаюсь, tidy () здесь будет недостаточно, так как не удалит пробелы (т. е. вкладки), заключенные в li ) и 2. этот код не добавляет требуемые <span> .
  • 0
    Обнаружив в скрипте ошибку, похоже, что он дублирует элемент li верхнего уровня всякий раз, когда создает новый ul (за исключением единственного исключения, являющегося ul верхнего уровня, как ни странно).

Ещё вопросы

Сообщество Overcoder
Наверх
Меню