如何突出显示位置的多个项目?

时间:2017-02-13 22:41:53

标签: javascript jquery

我正在尝试使用javascript解析W3c API JSON输出,并且考虑到它们的列(它们在字符串中的位置),我陷入了如何在某些关键字中放置一些跨度

我已经使用PHP重新组织了这些消息,因此我结束了以下内容:

    $.each(data.messages,function(line,msgs) {
        content = $("#l"+line).text();
        offset = 0;

        $.each(msgs,function(i,v) {
            position = v.firstColumn+v.hiliteStart+offset;
            length = v.hiliteLength;

            if (isNaN(position)) {
                position = v.lastColumn+v.hiliteStart;
            }

            content = content.substr(0, position)+'[span]'+content.substr(position, length)+'[/span]'+content.substr(position + length);
            offset += 13; //offset compensates for [span] and [/span]
        });
        //htmlentites function from locutus.io
        nst = htmlentities(content);
        nst = nst.replace(/\[span\]/g,'<span>');
        nst = nst.replace(/\[\/span\]/g,'</span>');
        $("#l"+line).html(nst);

      });

我的目标是在同一行HTML代码中突出显示几个错误和警告。

1 个答案:

答案 0 :(得分:0)

我首先将高亮范围定义为对象,然后从那里开始工作。例如,

  ranges = [{
    "begin": 145,
    "end": 155
  }, {
    "begin": 4,
    "end": 18
  }, {
    "begin": 4,
    "end": 18
  }, {
    "begin": 90,
    "end": 102
  }, {
    "begin": 4,
    "end": 41
  }];

这些是否在您的js中定义,或者它们是否来自服务器api取决于您以及您如何设计程序。但是,一旦定义了这些,就创建一个函数,该函数接收原始字符串和此范围集合,并将字符串(最好使用slice)分解为字符串段的集合。然后,您可以遍历细分,并根据需要附加<span></span>,然后将最终字符串放入DOM中。我无法从您的代码中告诉您从哪里获取索引。但是如果你可以将它们放在一个干净的结构中,那么你可以干净地分解你的字符串。

这里要记住的一件事是你可能有重叠的跨度。如果发生这种情况,您需要展平范围。这是一组功能,可以满足您的需求。只需使用您的文字和突出显示范围列表调用createHighlightedString即可。如有必要,它会使您的范围变平,并给您一个干净的结果。在此底部有一个指向工作样本的链接。

//Your implementation would look "something" like this
nst = htmlentities(content);
var ranges = [];//??? - GET YOUR RANGES DEFINED CLEANLY HERE
var highlightedString = createHighlightedString(ranges,nst);
$("#l"+line).html(highlightedString);

function createHighlightedString(ranges, text) {
  var flatRanges = flattenRanges(ranges);
  var inflatedRanges = inflateRanges(flatRanges, text.length);
  var filledRanges = fillRanges(inflatedRanges, text);
  var str = "";
  var index = 0;
  for (var i in filledRanges) {
    var range = filledRanges[i];
    var begin = range.begin, end = range.end;
    if (range.count > 0) {
      str += "<span class='highlight'>" + range.text + "</span>";
    } else {
      str += range.text;
    }
  }
  return str;
}

function flattenRanges(ranges) {
  var points = [];
  var flattened = [];
  for (var i in ranges) {
    if (ranges[i].end < ranges[i].begin) { //RE-ORDER THIS ITEM (BEGIN/END)
      var tmp = ranges[i].end+1; //RE-ORDER BY SWAPPING
      ranges[i].end = ranges[i].begin;
      ranges[i].begin = tmp;
    }
    points.push(ranges[i].begin);
    points.push(ranges[i].end);
  }
  //MAKE SURE OUR LIST OF POINTS IS IN ORDER
  points.sort(function(a, b){return a-b});
  //FIND THE INTERSECTING SPANS FOR EACH PAIR OF POINTS (IF ANY)
  //ALSO MERGE THE ATTRIBUTES OF EACH INTERSECTING SPAN, AND INCREASE THE COUNT FOR EACH INTERSECTION
  for (var i in points) {
    if (i==0 || points[i]==points[i-1]) continue;
    var includedRanges = ranges.filter(function(x){
      return (Math.max(x.begin,points[i-1]) < Math.min(x.end,points[i]));
    });
    if (includedRanges.length > 0) {
      var flattenedRange = {
        begin:points[i-1],
        end:points[i],
        count:0
      }
      for (var j in includedRanges) {
        var includedRange = includedRanges[j];
        for (var prop in includedRange) {
          if (prop != 'begin' && prop != 'end') {
            if (!flattenedRange[prop]) flattenedRange[prop] = [];
            flattenedRange[prop].push(includedRange[prop]);
          }
        }
        flattenedRange.count++;
      }
      flattened.push(flattenedRange);
    }
  }
  return flattened;
}

function inflateRanges(ranges, length=0) {
  var inflated = [];
  var lastIndex;
  for (var i in ranges) {
    if (i==0) {
      //IF THERE IS EMPTY TEXT IN THE BEGINNING, CREATE AN EMPTY RANGE
      if (ranges[i].begin > 0){
        inflated.push({
          begin:0,
          end:ranges[i].begin-1,
          count:0
        });
      }
      inflated.push(ranges[i]);
    } else {
      if (ranges[i].begin == ranges[i-1].end) {
        ranges[i-1].end--;
      }
      if (ranges[i].begin - ranges[i-1].end > 1) {
        inflated.push({
          begin:ranges[i-1].end+1,
          end:ranges[i].begin-1,
          count:0
        });
      }
      inflated.push(ranges[i]);
    }
    lastIndex = ranges[i].end;
  }
  //FOR SIMPLICITY, ADD ANY REMAINING TEXT AS AN EMPTY RANGE
  if (lastIndex+1 < length-1) {
    inflated.push({
      begin:lastIndex+1,
      end:length-1,
      count:0
    })
  }
  return inflated;
}

function fillRanges(ranges, text) {
  for (var i in ranges) {
    ranges[i].text = text.slice(ranges[i].begin,ranges[i].end+1);
  }
  return ranges;
}

工作示例:https://jsfiddle.net/shfpxp82/10/