string from list items after sortableJS has been applied - jquery-ui-sortable

I am tring to get a string from a list after it has been sorted using jquery ui sortable
Using a simple list ( without sorting)
<ul id = "description">
<li>one</li>
<li>two</li>
<li>three</li>
</ul>
and applying
$('#description').text().replace(/(\r\n|\n|\r)/gm," ");
I get: one two three
However if I make the list sortable and move items around, and using
function getOrder() {
alert($("#description").html());//gives a correct html ul
alert($("#description").text());// no spaces between words
var ans = $('#description').text().replace(/(\r\n|\n|\r)/gm," ");
alert("You got " + ans)
};
The output changes to three twoone or threetwoone - spacing messed up. $("description").html()
shows that the html is correct ( style="" gets added to the li tag for some reason) , but $('#description').text().replace(/(\r\n|\n|\r)/gm," "); does not give a properly spaced string.
Why does sorting change the behaviour and what can I do to resolve this? Appreciate any response please

To get the text, I would create a toString function:
function toString(element) {
var children = element.children;
var str = '';
for (var i = 0; i < children.length; i++) {
str += (!i ? '' : ' ') + children[i].textContent;
}
return str;
}
And then call that function with the HTMLElement (not jQuery object) of the list passed in as an argument.
This solution does not utilize jQuery, so you can use it with SortableJS or jQuery Sortable.

$.map( $('li'), function (element) { return $(element).text() }).join(' ');
works to get the list items into a properly spaced string

Related

Is it necessary to create <span> elements to register event listeners

I have a working web app that reads local .txt files and displays the content in a div element. I create a span element out of each word because I need to be able to select any word in the document and create an EEI (Essential Elements of Information) from the text. I then register a click handler on the containing div and let the event bubble up. The three functions below show reading the file, and parsing it, and populating the text div with spans:
function readInputFile(evt) {
reset();
var theFile = evt.target.files[0];
if(theFile) {
$("#theDoc").empty(); //Clean up any old docs loaded
var myReader = new FileReader();
var ta = document.getElementById("theDoc");
myReader.onload = function(e) {
parseTheDoc(e.target.result);
initialMarkup();
};
myReader.readAsText(theFile);
} else {
alert("Can not read input file: readInputFile()");
}
}
function parseTheDoc(docContents) {
var lines = docContents.split("\n");
var sentWords =[];
for(var i = 0; i < lines.length; i++) {
sentWords = lines[i].split(" ");
words = words.concat(sentWords);
words.push("<br>");
}
//examineWords(words);
createSpans(words);
}
function createSpans() {
for (var i = 0; i < words.length; i++) {
var currentWord = words[i];
if(currentWord !== "<br>") {
var $mySpan = $("<span />");
$mySpan.text(currentWord + " ");
$mySpan.attr("id", "word_" + i);
$("#theDoc").append($mySpan);
buildDocVector(currentWord, i, $mySpan);
}
else {
var $myBreak = $("<br>");
$myBreak.attr("id", "word_" + i);
$("#theDoc").append($myBreak);
buildDocVector("br", i, $myBreak);
}
}
//console.log("CreateSpans: Debug");
}
So basically a simple fileReader, split on \n, then tokenize on white space. I then create a span for each word, and a br element for each \n. It's not beautiful, but it satisfies the requirement, and works. My question is, is there a more efficient way of doing this? It just seems expensive to create all these spans, but my requirement is to annotate the doc and map any selected word to a data model/ontology. I can't think of a way to allow the user to select any word, or combination of words (control click) and then perform operations on them. This works, but with large docs (100 pages) I start having performance/memory issues. I understand this is more a design question and may not be appropriate, but I'd really like to know if there are more performant solutions.

Insert multiple lines of text into a Rich Text content control with OpenXML

I'm having difficulty getting a content control to follow multi-line formatting. It seems to interpret everything I'm giving it literally. I am new to OpenXML and I feel like I must be missing something simple.
I am converting my multi-line string using this function.
private static void parseTextForOpenXML(Run run, string text)
{
string[] newLineArray = { Environment.NewLine, "<br/>", "<br />", "\r\n" };
string[] textArray = text.Split(newLineArray, StringSplitOptions.None);
bool first = true;
foreach (string line in textArray)
{
if (!first)
{
run.Append(new Break());
}
first = false;
Text txt = new Text { Text = line };
run.Append(txt);
}
}
I insert it into the control with this
public static WordprocessingDocument InsertText(this WordprocessingDocument doc, string contentControlTag, string text)
{
SdtElement element = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>().FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>().Val == contentControlTag);
if (element == null)
throw new ArgumentException("ContentControlTag " + contentControlTag + " doesn't exist.");
element.Descendants<Text>().First().Text = text;
element.Descendants<Text>().Skip(1).ToList().ForEach(t => t.Remove());
return doc;
}
I call it with something like...
doc.InsertText("Primary", primaryRun.InnerText);
Although I've tried InnerXML and OuterXML as well. The results look something like
Example AttnExample CompanyExample AddressNew York, NY 12345 or
<w:r xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:t>Example Attn</w:t><w:br /><w:t>Example Company</w:t><w:br /><w:t>Example Address</w:t><w:br /><w:t>New York, NY 12345</w:t></w:r>
The method works fine for simple text insertion. It's just when I need it to interpret the XML that it doesn't work for me.
I feel like I must be super close to getting what I need, but my fiddling is getting me nowhere. Any thoughts? Thank you.
I believe the way I was trying to do it was doomed to fail. Setting the Text attribute of an element is always going to be interpreted as text to be displayed it seems. I ended up having to take a slightly different tack. I created a new insert method.
public static WordprocessingDocument InsertText(this WordprocessingDocument doc, string contentControlTag, Paragraph paragraph)
{
SdtElement element = doc.MainDocumentPart.Document.Body.Descendants<SdtElement>().FirstOrDefault(sdt => sdt.SdtProperties.GetFirstChild<Tag>().Val == contentControlTag);
if (element == null)
throw new ArgumentException("ContentControlTag " + contentControlTag + " doesn't exist.");
OpenXmlElement cc = element.Descendants<Text>().First().Parent;
cc.RemoveAllChildren();
cc.Append(paragraph);
return doc;
}
It starts the same, and gets the Content Control by searching for it's Tag. But then I get it's parent, remove the Content Control elements that were there and just replace them with a paragraph element.
It's not exactly what I had envisioned, but it seems to work for my needs.

I am getting 0 values for my array when I try to add DOM elements from a webpage, how to add values to lists in .each function?

On console it presents just empty array and 0's for all the elements on the Business Insider page with the specific selectors. How can I add each number (which is views on their site) as a list or string of numbers and then .length on the variable and push it to my html interface?
var request = require('request');
var cheerio = require('cheerio');
var bilist = new Array();
//var x = document.getElementById('bi-stats').innerHTML;
var url = 'http://www.businessinsider.com/moneygame';
request(url, function(err,resp,body)
{
if (err)
throw err;
$ = cheerio.load(body); //create the dom object string
$('span.hot').each(function() {
$(this).text().append(bilist);
console.log(bilist);
console.log(bilist.length);
});
});
function start() {
window.addEventListener('load', bi_list(), false);
}
So jQuery has a different syntax for the 'for' iterator.
The correct code is shown below which appends the text element that contains # of views of the site Business Insider.
$('span.hot').each(function(i, elem) {
bilist[i] = $(this).text();
});

jsTree customize <li> using the alternative JSON format along with AJAX

I am using the alternative JSON format along with AJAX to load data in tree. Now there is a new ask, I am required to add a new element at the end of <li> tag.
I have created sample URL to display what I am currently doing.
Tree crated using alternative JSON format along with AJAX
And how the new LI should appear
Tree created using hard coded HTML but shows how the LI should look like
I think I should be able to do this if I use HTML Data but since the project is already live with JSON format this would require me to change a lot so before I start making this major change I just wanted to check if this is possible using JSON and AJAX format or not.
So I got answer from Ivan - Answer
In short there is misc.js in the src folder which has question mark plugin, this is the best example of what I wanted to do.
I tweaked its code for my needs and here is the new code.
(function ($, undefined) {
"use strict";
var span = document.createElement('span');
span.className = 'glyphicons glyphicons-comments flip jstree-comment'
$.jstree.defaults.commenticon = $.noop;
$.jstree.plugins.commenticon = function (options, parent) {
this.bind = function () {
parent.bind.call(this);
};
this.teardown = function () {
if (this.settings.commenticon) {
this.element.find(".jstree-comment").remove();
}
parent.teardown.call(this);
};
this.redraw_node = function (obj, deep, callback, force_draw) {
var addCommentIcon = true;
var data = this.get_node(obj).data;
//....Code for deciding whether comment icon is needed or not based on "data"
var li = parent.redraw_node.call(this, obj, deep, callback, force_draw);
if (li && addCommentIcon) {
var tmp = span.cloneNode(true);
tmp.id = li.id + "_commenticon";
var $a = $("a", li);
$a.append(tmp);
}
return li;
};
};
})(jQuery);

Populate select in jqgrid filter toolbar

I've tried to populate a dropdownlist with values from my database. I've got the following code in my .js file:
function getDropdowndata() {
var sHTML;
var filter;
var url = "dropdown.json";
jQuery.getJSON(url, function (dddata) {
if (dddata.rows.length > 0) {
sHTML = "";
for (x = 0; x < dddata.rows.length; x++) {
sHTML += (dddata.rows[x].Type + ":" + dddata.rows[x].Type + ";");
}
filter = sHTML.substring(0, sHTML.length - 1);
}
});
return filter;
}
And in my Jqgrid list I've got the following:
editoptions: { value: ":All;" + getDropdowndata() }
The problem I've got with this code is that it seems that the function is being executed too early and because of that the dropdownlist contains nothing.
The reason for my assumption is that if I put an alert inside of the javascript function before the return, the dropdownlist is filled with the values and everything seems to work.
Any suggestions?
Instead of getting the data with a custom function using JSON, you might want to try using the built-in functionality for dynamic select fields (see documentation: select edittype ). All you do is specify a url where the code for the select element is generated.
colModel:[
{name:'colName',
editable:true,
edittype:'select',
formatter:'select',
editoptions:{dataUrl:'/path/to/generated/html/select'}
]
Then you just need to make sure that /path/to/generated/html/select returns all the right HTML code for a select element.