SilverStripe 3.1: Divide list into vertical columns (variable length) - multiple-columns

This may sound like an easy question but I'm a little stumped.
I've tried using Modulus and MultipleOf
https://docs.silverstripe.org/en/3/developer_guides/templates/syntax/
but this is giving me a list which goes horizontal. I want two columns The first column containing the first half of my listed data objects and the second column the second half.
Using CSS doesn't work as it splits the content and ignores the li containers so some of my list items (which are multiple lines each) get divided.
https://www.w3schools.com/Css/css3_multiple_columns.asp
Really I want to just be able to find the middle data object and divide it using html / css. Any suggestions welcome.
Here's an example of my list its shows 4 items, column 1 would contain item 1 & 2 and column 2, 3 & 4 (the actual list could be any length):
1 MAY 11 - 7.30PM - POWERSTOCK
THE HUT, DT6 3TB
BOX OFFICE: 01935 873555 / WEBSITE
TICKETS: £10.00/£8.00
2 OCT 13 - THE PLACE
BEDFORD
BOX OFFICE: 01234 354321 / WEBSITE
3 OCT 14 - PREVIEW: THE PLACE
BEDFORD
BOX OFFICE: 01234 354321 / WEBSITE
4 OCT 18 - CHILWELL ARTS CENTRE
BEESTON

You need a custom iterator property. You have $First, $Last, and $Middle made available to you through the core, but $Middle doesn't do what most people expect. Rather than return true on the median iteration, it's just anything between the first and last one, which isn't often helpful.
class MyIteratorProperties implements TemplateIteratorProvider
{
protected $totalItems;
protected $pos;
public static function get_template_iterator_variables()
{
return ['Median'];
}
public function iteratorProperties($pos, $totalItems)
{
$this->pos = $pos;
$this->totalItems = $totalItems;
}
public function Median()
{
return $this->pos == floor($this->totalItems/2);
}
}
And your template:
<% $loop $SomeItems %>
<% if $Median %></div><div ...><% end_if %>
<% end_loop %>

Related

Regex match any li of ul that contains text

I have a string
<ul><li>Option to add embroidered text personalization below design<br/>for only $1.00 per shirt and free setup</li><li>Men's Sizes: XS-6XL</li><li>Individually folded and bagged with size sticker for easy distribution</li><li>Ready to ship in 7 business days after art approval</li></ul>
Trying to match
<li>Men's Sizes: XS-6XL</li>
I am looking to take only the last <li></li> set that contains words
So for li that contains sizes I am looking to run something like:
(<li>).*?\b[sS]izes[ :]{1}.*?<\/li>
but that selects the first <li> instance instead of the closest.
EDIT: I can't use a html parser here like HTMLAgilityPack.
I'd use the pattern:
<li>[^<]*[Ss]izes[^<]*<\/li>
Which works like:
Element
Matches
<li>
The opening tag
[^<]*
Zero or more characters that are not the start of a new tag (<)
[Ss]izes
The keyword we are looking for
[^<]*
Zero or more characters that are not the start of a new tag (<)
<\/li>
The closing tag
Try it out!
And I'd take the last such matching element.
You can use innerHTML and innetText properties like this:
const str = "<ul><li>Option to add embroidered text personalization below design<br/>for only $1.00 per shirt and free setup</li><li>Men's Sizes: XS-6XL</li><li>Individually folded and bagged with size sticker for easy distribution</li><li>Ready to ship in 7 business days after art approval</li></ul>"
const el1 = document.createElement('div')
el1.innerHTML = str;
let liArr = el1.getElementsByTagName('li')
let resultsText = []
let resultsHTML = []
for (const listElement of liArr) {
if(listElement.innerText.indexOf('Size') >-1){
resultsText.push(listElement.innerText)
resultsHTML.push(listElement)
}
}
console.log('resultsText:::::::::::::')
console.log(resultsText)
console.log('resultsHTML::::::::::::')
console.log(resultsHTML)

AngularJS how to sum data from database in the view

I have a table, with one column for each day of the week, in which with a ng-repeat, I put the hours worked on a specific project in that week.
The data gets pulled from a database.
What I'm having trouble with is, each project can have different subprojects, and when this happens, they all get put in a rowspan under the same main project, as you can see in the image ( the "SU" Project has 2 subprojects "ghfgh" and "testtesttest").
Now, the total hours in the last column gets pulled as well from the database, where all the hours of a project in a specific week are summed.
How can I make that IF a project has subprojects, their hours that week get summed in a single rowspan as well? (in the image I put an arrow showing the result wanted)
If I use the same code to give the rowspan to the subprojects, it gives the right rowspan to the total column, but obviously only shows the hours of the first subproject (in this case "ghfgh")
<tr ng-repeat="p in vm.presences">
<td ng-if="p.showProject" rowspan="{{p.projectCount}}">{{p.projectName}}</td>
<td>{{p.description}}</td>
<td>{{p.monday}}</td>
<td>{{p.tuesday}}</td>
<td>{{p.wednesday}}</td>
<td>{{p.thursday}}</td>
<td>{{p.friday}}</td>
<td>{{p.saturday}}</td>
<td>{{p.sunday}}</td>
<td ng-if="p.showProject" rowspan="{{p.projectCount}}">{{p.total}}</td>
</tr>
and the code used to check if there are multiple entries of the same project in a given week, to group them in the same rowspan is
weeklyPresences.forEach((p, i) => {
const differentProject = i === 0 || weeklyPresences[i - 1].projectName !== p.projectName;
p.showProject = differentProject;
if (differentProject) {
p.projectCount = weeklyPresences.filter(pres => pres.projectName === p.projectName).length;
} else {
p.projectCount = weeklyPresences[i - 1].projectCount;
}
});
return weeklyPresences;
any idea on how I could group the hours of the subprojects?
I was thinking about some loop that checks if a project has multiple entries like the code above, if it doesn't, the var total stays the same, otherwise, it takes them and sums them in a new var.
var arr= [1, 2, 3];
var sum = arr.reduce((a, b) => a + b, 0);
console.log(sum); // 6

How to find the html tag node position with Html Agility Pack

I am trying to find the start/end positions of different Html tags inside my Html string by using Html Agility Pack.
Sample html string:
This is a custom made html string that will serve as an example for the StackOverflow question described above.
After successfully running the code I need to get 2 arrays with values from the start index of the a tags as follows:
int[] startIndex = new int[] { 11, 124 };
int[] endIndex = new int[] { 68, 176 };
Where 11 and 125 are the index positions that mark the begining of the a tag and 68 and 175 represents the last index position of the same tag.
I know that using the html agility pack HtmlNode I can get the LinePosition value that will give me the start index and along with the innerHtml.Lenght of the element I can calculate the end index position of the html element.
I was able to count the a elements by using:
int aNodesCount = htmlDoc.DocumentNode.SelectNodes("//a").Count;
And now I need to itereate through all of them and get the LinePosition values of each one. This is where I find myself stuck.
Well, that was pretty simple so I will post an answer for myself of others getting the same problem:
foreach (HtmlNode aNode in htmlDoc.DocumentNode.SelectNodes("//a"))
{
startIndex.Add(aNode.LinePosition);
endIndex.Add(aNode.LinePosition + aNode.OuterHtml.Length);
}

list() contains one element but it has matrix of string inside, how do I convert this element into matrix?

After converting JSON data into a list using jsonlite, i end up with one of the list looking like following
In this case, 10th element contain a list of 9 columns (always fixed) and 2 rows (varies everytime).
mat <- lset$data$comments$data[10]
mat
[[1]]
id can_remove created_time from.id
1 10152663742099258_10152663749369258 TRUE 2014-07-01T11:10:29+0000 10203711779968366
2 10152663742099258_10152663842204258 TRUE 2014-07-01T12:15:57+0000 706804257
3 10152663742099258_10152663929639258 TRUE 2014-07-01T13:25:28+0000 10152738599744416
4 10152663742099258_10152663976344258 TRUE 2014-07-01T13:59:33+0000 706804257
from.name like_count
1 Aileen Yeow 1
2 Tejas Damania 0
3 Sandeep Kulkarni 1
4 Tejas Damania 0
message
1 Lame statement
2 Don't forget, people like you only because they don't know you! <ed><U+00A0><U+00BD><ed><U+00B8><U+00A1>
3 ...for a second I thought it's Accenture Singapore office with some new theme similar to its brand!
4 This is shanghai and nothing to do with firm I work for <ed><U+00A0><U+00BD><ed><U+00B8><U+008E>
user_likes
1 FALSE
2 FALSE
3 TRUE
4 FALSE
Whole mat shows us as a list of [1]
As you can see, it contains list (within a list?). When i print mat then it shows a structure as seen above.
typeof(mat)
[1] "list"
substring(mat,1,100)
[1] "list(id = c(\"10152663742099258_10152663749369258\", \"10152663742099258_10152663842204258\", \"101526637"
I cant access specific elements (say message) from this. Nor I am able to convert this into a matrix of strings so I can access the elements in structured way.
I changed the fromJSON call parameter to by setting simplifyVector = FALSE (which is default set to true)
lset <- fromJSON(jsonobj, simplifyVector = F, flatten=TRUE, unicode = TRUE)
this changes the way mat is formed, code maintain nesting all the way down to each leaf element. I can keep going deeper using $ and find the string value only at leaf element!
lset$data[[x]]$comments$data[[y]]$from$name
That works for now! thanks for all the help

SSRS group total with semi dirty data

Data is Bill of Lading where I have to report items as well as lots and counts. Actual data is sent by other system that mixes total weight of an item on each line of lot details. I receive a textual generation of each Lot # and count from that lot per line on each line. Did I say dirty data?
I have grouped in a sub tablix to show only one item at a time just fine.
Now I need to get a total weight for the truck load. How do I Sum ONLY the first value for that item and skip all the second, third,... lots that comprise this item for my Tablix summary? Data below should show 8343 in the total weight.
Usually have 2 lots per item, may only be 1 lot 10% and may be more than 2 lots 15% of the time.
Will usually have at most 4 items per truck with most 75% of all trucks holding only 1 or 2 items.
item weight LotQuantity
ABC123 4655 4502052014 - 1200, 4512052014 - 2400
ABC123 4655 4502052014 - 1200, 4512052014 - 2400
ABC122 3688 4502052014 - 600, 4512052014 - 1200
ABC122 3688 4502052014 - 800, 4512052014 - 1400
TIA
Created functions in report code:
Dim wgt1 AS Double
Function addWgt(ByVal value AS Double)
wgt1 += value
End Function
Function getWT()
return wgt1
End Function
Dim Cnt AS Double
Function addCnt(ByVal value AS Double )
Cnt += value
End Function
Function getCNT()
return CNT
End Function
In an empty column I added the current weight as well as the current count via the addWGT()
For the report footer I just put in =Code.getWT()