The Problem:
I have a nested list on my configuration page that looks like this:
<a id='Save'>Save<a>
<ul id='configuration-list'>
<li id='e1'>Elem A
<ul>
<li id='ey'>Elem Y </li>
<li id='ex'>Elem X
<ul><!-- and so on until 5 levels of nesting --></ul>
</li>
<li id='ez'>Elem Z </li>
</ul>
</li>
<li id='e45'>
<ul>
<!-- more li's and ul's nesting here -->
</ul>
</li>
<!-- even more li's and ul's nesting here -->
<li id='eN'>
</li>
</ul>
Each li on the list can have another unordered list inside, which contains li, that can contain other unordered list inside.
All the list are sortable, using jquery ui.sortable plugin. Items cannot be switched through list.
The total of nodes in the list is more than 1k.
When the configuration is saved (Save link) I have to send the list order configuration (form the first to the deepest node) to the server which will parse it and save all the elements order in the database. For this, php is used.
The questions:
Whats the 'best' or the less wrong way to parse the configuration, and how should I pass it to my php parser?
Is there a method similar to $('#configuration-list').sortable('serialize') or $('#configuration-list').sortable('toArray') that generates me a xml, JSON or similar with all the structure? An extension of ui.sortable or another plugin that have this functionality?
Thanks in advance.
It's not clear if <li> contains radio/checks/textboxes, so the suggestion may vary. A lot of time ago (5-6 years i think) I've encountered similar situation, and that time i've used names recalling array structures (if i remember correctly, too old memories :/)
I.e.
<input type="text" name="nodes[node1][item1]" />
<input type="text" name="nodes[node1][item2]" />
Maybe it can help you.
.sortable('serialize') takes an optional second parameter (or, serialize() takes a single parameter. God I hate the plugin apis):
make sure the id attributes include an
underscore. They must be in the form:
"set_number" For example, a 3 element
list with id attributes foo_1, foo_5,
foo_2 will serialize to
foo[]=1&foo[]=5&foo[]=2. You can use
an underscore, equal sign or hyphen to
separate the set and number. For
example foo=1 or foo-1 or foo_1 all
serialize to foo[]=1.
When you are saving large nested sets you should consider the Nested Set Model, it's a different approach for storing hierarchical data in a flat table, which MySQL or any other non-XML database is. NSM works with two numbers, left and right for defining the range of a set and all childs in it.
A link which was very usefull to me:
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/
In your PHP controller (or whereever you handle / control your data before saving it) you can simply loop through your configurations. I prefer to use array values for forminputs in this case, just like the other posters said.
You should use form element for this, i prefer hidden fields, give the name of the field something like node_# where # represents the parent-id for the child. And the value must then be the ID of the current child.
Use a simple for-loop to loopthrough 'node_#' and get the arrayvalues from the element-value 1 by 1. Increasing the sortorder for each node with the same parent by 1 when a node passes by.
Sample:
<input type="hidden" name="node_1[]" value="4"/>
<input type="hidden" name="node_1[]" value="5"/>
<input type="hidden" name="node_1[]" value="6"/>
<input type="hidden" name="node_1[]" value="7"/>
Then nodes 4 t/m 7 will be stored as an array in $_POST["node_1"].
Related
There is an HTML file (whose contents I do not control) that has several input elements all with the same fixed id attribute of "search_query". The contents of the file can change, but I know that I always want to get the second input element with the id attribute "search_query".
I need an XPath expression to do this. I tried //input[#id="search_query"][2] but that does not work. Here is an example XML string where this query failed:
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
Keep in mind that that the above is merely an example and the other HTML code can be quite different and the input elements can appear anywhere with no consistent document structure (except that I am guaranteed there will always be at least two input elements with an id attribute of "search_query").
What is the correct XPath expression?
This is a FAQ:
//somexpression[$N]
means "Find every node selected by //somexpression that is the $Nth child of its parent".
What you want is:
(//input[#id="search_query"])[2]
Remember: The [] operator has higher precedence (priority) than the // abbreviation.
This seems to work:
/descendant::input[#id="search_query"][2]
I go this from "XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition" by Michael Kay.
There is also a note in the "Abbreviated Syntax" section of the XML Path Language specification http://www.w3.org/TR/xpath/#path-abbrev that provided a clue.
There is an HTML file (whose contents I do not control) that has several input elements all with the same fixed id attribute of "search_query". The contents of the file can change, but I know that I always want to get the second input element with the id attribute "search_query".
I need an XPath expression to do this. I tried //input[#id="search_query"][2] but that does not work. Here is an example XML string where this query failed:
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
<div>
<form>
<input id="search_query" />
</form>
</div>
Keep in mind that that the above is merely an example and the other HTML code can be quite different and the input elements can appear anywhere with no consistent document structure (except that I am guaranteed there will always be at least two input elements with an id attribute of "search_query").
What is the correct XPath expression?
This is a FAQ:
//somexpression[$N]
means "Find every node selected by //somexpression that is the $Nth child of its parent".
What you want is:
(//input[#id="search_query"])[2]
Remember: The [] operator has higher precedence (priority) than the // abbreviation.
This seems to work:
/descendant::input[#id="search_query"][2]
I go this from "XSLT 2.0 and XPath 2.0 Programmer's Reference, 4th Edition" by Michael Kay.
There is also a note in the "Abbreviated Syntax" section of the XML Path Language specification http://www.w3.org/TR/xpath/#path-abbrev that provided a clue.
I have a need in Magento to provide an array custom product attribute that outputs all of its values as list items. The basic premise is a list of product ingredients... on a per product basis we need to enter (for example) water, salt, colourings - and for those to be rendered as a list on the front end.
My logic so far has been to use the standard text field attribute, entering comma separated values in the back-end and then to try and use that string as an array from which I can use foreach to create the unordered list.
So far I can echo the entire string as just one list item, but rendering the string as an array of its individual values has so far stumped me! See below...
The Ingredients text field attribute has a value of "water", "salt", "colourings". - the addition of quote marks and commas is only the assumption that this would pre-format the list ready to be an array.
<?php
$ingredientsArrayContent = $this->getProduct()->getSpa_productingredients();
$ingredientsArray = array($ingredientsArrayContent);
?>
<ul>
<?php
reset($ingredientsArray);
foreach ($ingredientsArray as $ingredientsValue) {
echo "<li>$ingredientsValue</li>\n";
}
?>
</ul>
So on the front end this is outputting:
<ul>
<li>"water", "salt", "colourings"</li>
</ul>
What of course I am looking to achieve is:
<ul>
<li>water</li>
<li>salt</li>
<li>colourings</li>
</ul>
Am I over complicating this and missing something really obvious even in Magento? Any pointers greatly appreciated!!
Perhaps instead of:
$ingredientsArray = array($ingredientsArrayContent);
try using:
$ingredientsArray = array(explode(",",$ingredientsArrayContent));
Depending on whether your attribute is set as: "water,salt,colourings" or "water, salt, colourings" your delimiter might need to change or how you set your attribute values might need to change.
UPDATE AT THE BOTTOM
Maybe somebody could help with this... been struggling with it for days and i'm blocked :/
For a content-cleaner solution i'm working in, i'm trying to convert some pure-text numbered lists, like:
1 Foo
1.1 Foo 1
1.2 Foo 2
2 Bar
2.1 Bar 1
2.2 Bar 2
2.2.1 Bar 2.1
2.2.2 Bar 2.2
2.3 Bar 3
3 Z Another root item
... into correct nested html lists ...
<ul>
<li>Foo
<ul>
<li>Foo 1</li>
<li>Foo 2</li>
</ul>
</li>
<li>Bar
<ul>
<li>Bar 1</li>
<li>Bar 2
<ul>
<li>Bar 2.1</li>
<li>Bar 2.2</li>
</ul>
</li>
<li>Bar 3</li>
</ul>
<li>Another root item</li>
</ul>
Some things that may help:
No need for the result to be correctly indented, just surrounded by the correct html tags
No need to locate the list inside another text, can sume i already have only the list
No need for great performance, regexp, itaration... whatever works is fine
No need for especific language solution, PHP, Python, Javascript, Pseudocode... is fine
Can asume " " (space) as the only separator after the "1.2.3 " list text
Can asume lines are already in the correct order, no need to order them at all
UPDATE TLTR (Not homework, but real world usage)
Sorry for looking so "homework not done", my fault. English is not my language and i tried to be maybe to concise.
What i'm trying to do is to make it easier for my workmates to format text to correct html from unknow sources.
Up to day i managed to (you can see the full screenshot here http://twitpic.com/907aw5/ as i can't attach images being my first question and no reputation):
I get the original text and do a strip_tags on it to delete any incorrect HTML it can have
I insert it into a textarea
I integrated a Javascript editor ( Codemirror http://codemirror.net ) with the specifications for HTML
I injected an edition bar with the most common tags we use, as my workmates doesn't know a word about HTML
As part of the cleaning options, i set two hotkeys that makes an ul / ol of the selected text (breaking in the \n chars)
When the user saves, i run HTMLTidy on it for it to became as cleaner as posible (indent, delete propietary tags, etc...)
Just to finish, as you can see in the above screenshot, i have a lot of texts with the 1.2.3 "organization", and it will be of much help to be able to get a nested list solution out of this kind of text.
UPDATE (The especific needs)
Now the explanation of "why" i used so many bullets for asumptions:
No need for the result to be correctly indented, just surrounded by the correct html tags (Because after this, when the user hit Save button, i run htmltidy on it, so it get indented)
No need to locate the list inside another text, can sume i already have only the list (Because i run the code over the user-selected text in the editor, so i can sume he selected the correct list)
No need for great performance, regexp, itaration... whatever works is fine (As it an human-use, point-click, point-click, i don't mind if it takes 0.0001 seconds per use, or 0.1)
No need for especific language solution, PHP, Python, Javascript, Pseudocode... is fine (I intend to use it in javascript/jQuery, but what i need is just the logic, as i'm blocked... i can tarnslate it if the solution is in another language)
Can asume " " (space) as the only separator after the "1.2.3 " list text (As it is the 99% of my text-cases)
Can asume lines are already in the correct order, no need to order them at all (As you can see in the screenshot, that text is human-entered, and i asume they inserted it in the correct order)
Sorry again for not being clear enought, just my first question in Stackoverflow, and i didn't realize it will look like homework, my fault.
Just for funsies, I went ahead and wrote a solution to your problem using PHP:
function helper_func($m)
{
static $r=0;
$o='';
$l=preg_match_all("#\d+#",$m[1],$n);
while($l < $r)
{
$r--;
$o .= '</li></ul>';
}
if($l == $r)return $l == 0?$o.$m[0]:$o.'</li><li>'.$m[0];
else $o=$m[0];
while($l > $r)
{
$r++;
$o = '<ul><li>'.$o;
}
return $o;
}
echo preg_replace_callback("#^([0-9.]*).*$#m","helper_func",$input);
However, in deference to this being homework, I included a deliberate error: for it to come out correctly, you need to make a single small change to $input before passing it in... Have fun :)
I'm implementing a sortable list of images with jquery in a Zend Framework application.
I just can't get the .sortable('serialize') method to return more than an empty string.
When I try with a few simple examples outside my application it works.
Does it matter that the snippet below is wrapped in various other and other tags. I think it shouldn't. The unordered list should be found just by the id, right?
HTML:
<ul id="mylist">
<li id="1">
<div>
<img src="image_1.jpg" />
<p class="value_item">some text</p>
</div>
</li>
<li id="2">
<div>
<img src="image_2.jpg" />
<p class="value_item">some text</p>
</div>
</li>
</ul>
JavaScript:
$(document).ready(function() {
$('#mylist').sortable({
update: function() {
var order = $('#mylist').sortable('serialize');
alert(order);
}
});
});
http://api.jqueryui.com/sortable/#method-serialize
If serialize returns an empty string, make sure the id attributes include an underscore. They must be in the form: "set_number" For example, a 3 element list with id attributes foo_1, foo_5, foo_2 will serialize to foo[]=1&foo[]=5&foo[]=2. You can use an underscore, equal sign or hyphen to separate the set and number. For example foo=1 or foo-1 or foo_1 all serialize to foo[]=1.
Jquery runs into problems when you use non-compliant ids.
Ids are not allowed to begin with a number. They can have numbers in them, just not as the first character.
(link update)
hi, I stumbled across a similiar problem a few days ago, though in my case it was important to keep the order of the elements intact. I coded a small plugin which will allow you to serialize ul and ol lists of arbitrary depth and complexity:
serializeTree