Scraped data not printing to csv/xlsx file - web-scraping

I'm trying to scrape data and store it in a csv or xlsx file, but when I run my code, the file returns empty.
When I used a break to stop the iterator after one cycle, I found the code held a row of the data I want. The end goal is to write this data, row-by-row, into the file. If it helps to know, I'm using beautifulsoup4.
Here is the code:
from bs4 import BeautifulSoup
import requests
import xlsxwriter
url = 'https://www.rwaq.org/courses'
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
base = 'https://www.rwaq.org'
course_div = soup.find_all('div', attrs={'class': 'course-info'})
course_links = [base + item.h3.a['href'] for item in course_div]
row = 0
for link in course_links:
inner_page = requests.get(link)
inner_soup = BeautifulSoup(inner_page.content, 'html.parser')
course_name = inner_soup.find('div', attrs={'class': 'page-title'}).h2.text
course_lecturer_name = inner_soup.find('div', attrs={'class': 'instructor-details'}).a.text.strip()
course_desc = inner_soup.find('div', attrs={'class': 'lecture_desc'}).p.text.strip()
if inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid ul'):
course_manhag = inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid p'):
course_manhag = inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid p').text
else:
course_manhag = ''
if inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid ul'):
course_require = inner_soup.select_one(
'#organization div.course-content div:nth-child(5) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid p'):
course_require = inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid p').text
else:
course_require = ''
if inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid ul'):
course_out = inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid p'):
course_out = inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid p').text
else:
course_out = ''
course_company = inner_soup.select_one(
'body div.container-fluid div div.subject-cover div.cover-info div div.subject-organization p a').text
course_date_from = inner_soup.select_one('p.subject-date').text.strip()[3:16]
if inner_soup.select_one('p.subject-date') is True:
course_date_to = inner_soup.select_one('p.subject-date').text.strip()[31:]
else:
course_date_to = ''
course_status = inner_soup.select_one('p.subject-date span').text
course_lecturer_link = [base + li.a['href'] for li in
inner_soup.find_all("div", attrs={'class': 'instructor-details'})]
course_iframe = inner_soup.select_one('iframe').attrs["src"]
course_promo_link = course_iframe[:24] + 'watch?v=' + course_iframe[30:course_iframe.find('?')]
wb = xlsxwriter.Workbook('file001.xlsx')
sheet = wb.add_worksheet()
sheet.write(row, 0, course_promo_link)
sheet.write_row(row, 1, course_lecturer_link)
sheet.write(row, 2, course_desc)
sheet.write(row, 3, course_out)
sheet.write(row, 4, course_status)
sheet.write(row, 5, course_name)
sheet.write(row, 6, course_date_from)
sheet.write(row, 7, course_date_to)
sheet.write(row, 8, course_manhag)
sheet.write(row, 9, course_require)
row += 1
wb.close()
break

well I get errors running your code so I can't test. But the first initial thing I would try is take wb = xlsxwriter.Workbook('file001.xlsx') and wb.close() out of the for loop. My initial thought is you're over writing the file each time. So something like:
from bs4 import BeautifulSoup
import requests
import xlsxwriter
url = 'https://www.rwaq.org/courses'
response = requests.get(url)
soup = BeautifulSoup(response.content, 'html.parser')
base = 'https://www.rwaq.org'
course_div = soup.find_all('div', attrs={'class': 'course-info'})
course_links = [base + item.h3.a['href'] for item in course_div]
#Initialize your file/workbook
wb = xlsxwriter.Workbook('C:/file001.xlsx')
sheet = wb.add_worksheet()
row = 0
for link in course_links:
inner_page = requests.get(link)
inner_soup = BeautifulSoup(inner_page.content, 'html.parser')
course_name = inner_soup.find('div', attrs={'class': 'page-title'}).h2.text
course_lecturer_name = inner_soup.find('div', attrs={'class': 'instructor-details'}).a.text.strip()
course_desc = inner_soup.find('div', attrs={'class': 'lecture_desc'}).p.text.strip()
if inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid ul'):
course_manhag = inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid p'):
course_manhag = inner_soup.select_one('#organization div.course-content div:nth-child(4) div.row-fluid p').text
else:
course_manhag = ''
if inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid ul'):
course_require = inner_soup.select_one(
'#organization div.course-content div:nth-child(5) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid p'):
course_require = inner_soup.select_one('#organization div.course-content div:nth-child(5) div.row-fluid p').text
else:
course_require = ''
if inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid ul'):
course_out = inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid ul').text
elif inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid p'):
course_out = inner_soup.select_one('#organization div.course-content div:nth-child(6) div.row-fluid p').text
else:
course_out = ''
course_company = inner_soup.select_one(
'body div.container-fluid div div.subject-cover div.cover-info div div.subject-organization p a').text
course_date_from = inner_soup.select_one('p.subject-date').text.strip()[3:16]
if inner_soup.select_one('p.subject-date') is True:
course_date_to = inner_soup.select_one('p.subject-date').text.strip()[31:]
else:
course_date_to = ''
course_status = inner_soup.select_one('p.subject-date span').text
course_lecturer_link = [base + li.a['href'] for li in
inner_soup.find_all("div", attrs={'class': 'instructor-details'})]
course_iframe = inner_soup.select_one('iframe').attrs["src"]
course_promo_link = course_iframe[:24] + 'watch?v=' + course_iframe[30:course_iframe.find('?')]
sheet.write(row, 0, course_promo_link)
sheet.write(row, 1, course_lecturer_link)
sheet.write(row, 2, course_desc)
sheet.write(row, 3, course_out)
sheet.write(row, 4, course_status)
sheet.write(row, 5, course_name)
sheet.write(row, 6, course_date_from)
sheet.write(row, 7, course_date_to)
sheet.write(row, 8, course_manhag)
sheet.write(row, 9, course_require)
row += 1
# Close it once all rows are written
wb.close()

Related

How to show logical values in rhandsontable as the check boxes on UI

I have one question on how to show the logical values in rhandsontable as check boxes on UI. Here is the code originally from (https://cran.r-project.org/web/packages/rhandsontable/vignettes/intro_rhandsontable.html).
library(rhandsontable)
DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = FALSE)
col_highlight = 2
row_highlight = c(5, 7)
rhandsontable(DF, col_highlight = col_highlight,
row_highlight = row_highlight,
width = 550, height = 300) %>%
hot_cols(renderer = "
function(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
tbl = this.HTMLWidgets.widgets[0]
hcols = tbl.params.col_highlight
hcols = hcols instanceof Array ? hcols : [hcols]
hrows = tbl.params.row_highlight
hrows = hrows instanceof Array ? hrows : [hrows]
if (hcols.includes(col) && hrows.includes(row)) {
td.style.background = 'red';
}
else if (hcols.includes(col)) {
td.style.background = 'lightgreen';
}
else if (hrows.includes(row)) {
td.style.background = 'pink';
}
return td;
}")
As you can see, the bool column was not shown as the check boxex and they are not editable too. Does anyone know how to (1) show the logic column as check boxes on UI, and (2) how to make that column as editable? Any your input will be greatly apprreciated.
This is because you can't use a text renderer to render boolean values. You need to use CheckboxRenderer instead. Here is how to fix:
library(rhandsontable)
DF = data.frame(val = 1:10, bool = TRUE, big = LETTERS[1:10],
small = letters[1:10],
dt = seq(from = Sys.Date(), by = "days", length.out = 10),
stringsAsFactors = FALSE)
col_highlight = 2
row_highlight = c(5, 7)
rhandsontable(DF, col_highlight = col_highlight,
row_highlight = row_highlight,
width = 550, height = 300) %>%
hot_cols(renderer = "
function(instance, td, row, col, prop, value, cellProperties) {
console.log(typeof value)
if(typeof value === 'boolean') {
Handsontable.renderers.CheckboxRenderer.apply(this, arguments);
} else {
Handsontable.renderers.TextRenderer.apply(this, arguments);
}
tbl = this.HTMLWidgets.widgets[0]
console.log(value)
hcols = tbl.params.col_highlight
hcols = hcols instanceof Array ? hcols : [hcols]
hrows = tbl.params.row_highlight
hrows = hrows instanceof Array ? hrows : [hrows]
if (hcols.includes(col) && hrows.includes(row)) {
td.style.background = 'red';
}
else if (hcols.includes(col)) {
td.style.background = 'lightgreen';
}
else if (hrows.includes(row)) {
td.style.background = 'pink';
}
return td;
}")

add different widgets to each wxnotebook tab permanently in a txt file or sqlite

Please how can I add permanently different widgets in the tabs and save them permanently
<html>
<pre>
import wx
tabs = []
with open('test.txt','r') as file:
for element in file.readlines():
tabs.append(element)
class TabPanel(wx.Panel):
def __init__(self, parent, pageNum):
self.parent = parent
self.pageNum = pageNum
wx.Panel.__init__(self, parent=parent)
class DemoFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Notebook", size=(600,400))
panel = wx.Panel(self)
self.tab_num = len(tabs)
self.notebook = wx.Notebook(panel)
for tab in tabs:
name = "Page " + str(tab)
tab = TabPanel(self.notebook, 1)
self.notebook.AddPage(tab, name)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(panel, label="Add Page")
btn.Bind(wx.EVT_BUTTON, self.addPage)
sizer.Add(btn)
panel.SetSizer(sizer)
self.Layout()
self.Show()
def addPage(self, event):
self.tab_num += 1
new_tab = TabPanel(self.notebook, self.tab_num)
self.notebook.AddPage(new_tab, "Page %s" % self.tab_num)
tabs.append(self.tab_num)
print()
with open('test.txt','a+') as file:
file.write(str(self.tab_num))
file.write('\n')
if __name__ == "__main__":
app = wx.App(False)
frame = DemoFrame()
app.MainLoop()
</pre>
</html>
Something like this should get you started (sorry not readdly familiar with python):
class DemoFrame(wx.Frame):
def __init__(self):
self.tab_num = 1
wx.Frame.__init__(self, None, wx.ID_ANY, "Notebook", size=(600,400))
panel = wx.Panel(self)
with open( "test.txt", "r" as file:
self.tab_num = file.read()
self.notebook = wx.Notebook(panel)
for tab in [1..self.tab_num]:
name = "Page " + str(tab)
tab = TabPanel(self.notebook, 1)
self.notebook.AddPage(tab, name)
sizer = wx.BoxSizer(wx.VERTICAL)
sizer.Add(self.notebook, 1, wx.ALL|wx.EXPAND, 5)
btn = wx.Button(panel, label="Add Page")
btn.Bind(wx.EVT_BUTTON, self.addPage)
sizer.Add(btn)
panel.SetSizer(sizer)
self.Layout()
self.Show()
def addPage(self, event):
self.tab_num += 1
new_tab = TabPanel(self.notebook, self.tab_num)
self.notebook.AddPage(new_tab, "Page %s" % self.tab_num)
tabs.append(self.tab_num)
print()
with open('test.txt','a+') as file:
file.write(str(self.tab_num))
file.write('\n')
if __name__ == "__main__":
app = wx.App(False)
frame = DemoFrame()
app.MainLoop()

networkD3 package: show node names of all connected nodes when hovering over

Using the forceNetwork function of the networkD3 package, it is possible to create an interactive network graph that can show the node names when hovering over them.
I am trying to create a graph that not only shows the node where the mouse is hovering over, but also all neighboring nodes, i.e. all nodes that are directly connected to the selected node. However, it should not show any nodes that are not directly connected to the node.
Although I found the argument opacityNoHover, it will affect all the nodes that the mouse is not covering and not just the nodes with a direct connection.
library(networkD3)
# example data
data(MisLinks)
data(MisNodes)
# creating the plot
forceNetwork(Links = MisLinks, Nodes = MisNodes,
Source = "source", Target = "target",
Value = "value", NodeID = "name",
Group = "group", opacity = 1, fontSize = 15,
opacityNoHover = 0)
You could re-write the mouseover and mouseout functions and override them with htmlwidgets::onRender...
library(networkD3)
library(htmlwidgets)
data(MisLinks)
data(MisNodes)
fn <- forceNetwork(Links = MisLinks, Nodes = MisNodes, Source = "source",
Target = "target", Value = "value", NodeID = "name",
Group = "group", opacity = 1, fontSize = 15,
opacityNoHover = 0)
customJS <- '
function(el,x) {
var link = d3.selectAll(".link")
var node = d3.selectAll(".node")
var options = { opacity: 1,
clickTextSize: 10,
opacityNoHover: 0.1,
radiusCalculation: "Math.sqrt(d.nodesize)+6"
}
var unfocusDivisor = 4;
var links = HTMLWidgets.dataframeToD3(x.links);
var linkedByIndex = {};
links.forEach(function(d) {
linkedByIndex[d.source + "," + d.target] = 1;
linkedByIndex[d.target + "," + d.source] = 1;
});
function neighboring(a, b) {
return linkedByIndex[a.index + "," + b.index];
}
function nodeSize(d) {
if(options.nodesize){
return eval(options.radiusCalculation);
}else{
return 6}
}
function mouseover(d) {
var unfocusDivisor = 4;
link.transition().duration(200)
.style("opacity", function(l) { return d != l.source && d != l.target ? +options.opacity / unfocusDivisor : +options.opacity });
node.transition().duration(200)
.style("opacity", function(o) { return d.index == o.index || neighboring(d, o) ? +options.opacity : +options.opacity / unfocusDivisor; });
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", function(d){return nodeSize(d)+5;});
node.select("text").transition()
.duration(750)
.attr("x", 13)
.style("stroke-width", ".5px")
.style("font", 24 + "px ")
.style("opacity", function(o) { return d.index == o.index || neighboring(d, o) ? 1 : 0; });
}
function mouseout() {
node.style("opacity", +options.opacity);
link.style("opacity", +options.opacity);
d3.select(this).select("circle").transition()
.duration(750)
.attr("r", function(d){return nodeSize(d);});
node.select("text").transition()
.duration(1250)
.attr("x", 0)
.style("font", options.fontSize + "px ")
.style("opacity", 0);
}
d3.selectAll(".node").on("mouseover", mouseover).on("mouseout", mouseout);
}
'
onRender(fn, customJS)

Angular 7 lava effect animation

I have an Angular 7 app with a home page containing a large coloured block (enough to fill the page) at the top with a header and some images. I want to put some lava effect animations into the background similar to this
code in case link is removed:
HTML:
<canvas id="lamp-anim" class="lamp-anim" width="1034" height="613"></canvas>
CSS:
body {
background: #f857a6; /* fallback for old browsers */
background: -webkit-linear-gradient(to top, #ff5858, #f857a6); /* Chrome
10-25, Safari 5.1-6 */
background: linear-gradient(to top, #ff5858, #f857a6); /* W3C, IE 10+/
Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
JS:
window.lavaAnimation = function() {
"use strict";
var t, i = {
screen: {
elem: null,
callback: null,
ctx: null,
width: 0,
height: 0,
left: 0,
top: 0,
init: function(t, i, s) {
return this.elem = document.getElementById(t), this.callback = i || null, "CANVAS" == this.elem.tagName && (this.ctx = this.elem.getContext("2d")), window.addEventListener("resize", function() {
this.resize()
}.bind(this), !1), this.elem.onselectstart = function() {
return !1
}, this.elem.ondrag = function() {
return !1
}, s && this.resize(), this
},
resize: function() {
var t = this.elem;
for (this.width = t.offsetWidth, this.height = t.offsetHeight, this.left = 0, this.top = 0; null != t; t = t.offsetParent) this.left += t.offsetLeft, this.top += t.offsetTop;
this.ctx && (this.elem.width = this.width, this.elem.height = this.height), this.callback && this.callback()
}
}
},
s = function(t, i) {
this.x = t, this.y = i, this.magnitude = t * t + i * i, this.computed = 0, this.force = 0
};
s.prototype.add = function(t) {
return new s(this.x + t.x, this.y + t.y)
};
var h = function(t) {
var i = .1,
h = 1.5;
this.vel = new s((Math.random() > .5 ? 1 : -1) * (.2 + .25 * Math.random()), (Math.random() > .5 ? 1 : -1) * (.2 + Math.random())), this.pos = new s(.2 * t.width + Math.random() * t.width * .6, .2 * t.height + Math.random() * t.height * .6), this.size = t.wh / 15 + (Math.random() * (h - i) + i) * (t.wh / 15), this.width = t.width, this.height = t.height
};
h.prototype.move = function() {
this.pos.x >= this.width - this.size ? (this.vel.x > 0 && (this.vel.x = -this.vel.x), this.pos.x = this.width - this.size) : this.pos.x <= this.size && (this.vel.x < 0 && (this.vel.x = -this.vel.x), this.pos.x = this.size), this.pos.y >= this.height - this.size ? (this.vel.y > 0 && (this.vel.y = -this.vel.y), this.pos.y = this.height - this.size) : this.pos.y <= this.size && (this.vel.y < 0 && (this.vel.y = -this.vel.y), this.pos.y = this.size), this.pos = this.pos.add(this.vel)
};
var e = function(t, i, e, n, a) {
this.step = 5, this.width = t, this.height = i, this.wh = Math.min(t, i), this.sx = Math.floor(this.width / this.step), this.sy = Math.floor(this.height / this.step), this.paint = !1, this.metaFill = r(t, i, t, n, a), this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0], this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1], this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0], this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1], this.grid = [], this.balls = [], this.iter = 0, this.sign = 1;
for (var o = 0; o < (this.sx + 2) * (this.sy + 2); o++) this.grid[o] = new s(o % (this.sx + 2) * this.step, Math.floor(o / (this.sx + 2)) * this.step);
for (var l = 0; e > l; l++) this.balls[l] = new h(this)
};
e.prototype.computeForce = function(t, i, s) {
var h, e = s || t + i * (this.sx + 2);
if (0 === t || 0 === i || t === this.sx || i === this.sy) h = .6 * this.sign;
else {
h = 0;
for (var r, n = this.grid[e], a = 0; r = this.balls[a++];) h += r.size * r.size / (-2 * n.x * r.pos.x - 2 * n.y * r.pos.y + r.pos.magnitude + n.magnitude);
h *= this.sign
}
return this.grid[e].force = h, h
}, e.prototype.marchingSquares = function(t) {
var i = t[0],
s = t[1],
h = t[2],
e = i + s * (this.sx + 2);
if (this.grid[e].computed === this.iter) return !1;
for (var r, n = 0, a = 0; 4 > a; a++) {
var l = i + this.ix[a + 12] + (s + this.ix[a + 16]) * (this.sx + 2),
d = this.grid[l].force;
(d > 0 && this.sign < 0 || 0 > d && this.sign > 0 || !d) && (d = this.computeForce(i + this.ix[a + 12], s + this.ix[a + 16], l)), Math.abs(d) > 1 && (n += Math.pow(2, a))
}
if (15 === n) return [i, s - 1, !1];
5 === n ? r = 2 === h ? 3 : 1 : 10 === n ? r = 3 === h ? 0 : 2 : (r = this.mscases[n], this.grid[e].computed = this.iter);
var p = this.step / (Math.abs(Math.abs(this.grid[i + this.plx[4 * r + 2] + (s + this.ply[4 * r + 2]) * (this.sx + 2)].force) - 1) / Math.abs(Math.abs(this.grid[i + this.plx[4 * r + 3] + (s + this.ply[4 * r + 3]) * (this.sx + 2)].force) - 1) + 1);
return o.lineTo(this.grid[i + this.plx[4 * r] + (s + this.ply[4 * r]) * (this.sx + 2)].x + this.ix[r] * p, this.grid[i + this.plx[4 * r + 1] + (s + this.ply[4 * r + 1]) * (this.sx + 2)].y + this.ix[r + 4] * p), this.paint = !0, [i + this.ix[r + 4], s + this.ix[r + 8], r]
}, e.prototype.renderMetaballs = function() {
for (var t, i = 0; t = this.balls[i++];) t.move();
for (this.iter++, this.sign = -this.sign, this.paint = !1, o.fillStyle = this.metaFill, o.beginPath(), i = 0; t = this.balls[i++];) {
var s = [Math.round(t.pos.x / this.step), Math.round(t.pos.y / this.step), !1];
do s = this.marchingSquares(s); while (s);
this.paint && (o.fill(), o.closePath(), o.beginPath(), this.paint = !1)
}
};
var r = function(t, i, s, h, e) {
var r = o.createRadialGradient(t / 1, i / 1, 0, t / 1, i / 1, s);
return r.addColorStop(0, h), r.addColorStop(1, e), r
};
if (document.getElementById("lamp-anim")) {
var n = function() {
requestAnimationFrame(n), o.clearRect(0, 0, a.width, a.height), t.renderMetaballs()
},
a = i.screen.init("lamp-anim", null, !0),
o = a.ctx;
a.resize(), t = new e(a.width, a.height, 6, "#3494E6", "#EC6EAD")
}
return {
run: n
}
}();
if (document.getElementById('lamp-anim')) {
lavaAnimation.run();
}
setTimeout(function() {
$('.js-works-d-list').addClass('is-loaded');
}, 150);
Is it possible to convert/do this in angular animations? Are they flexible enough to do this sort of (what id call advanced) animation?
I think the question of 'can I convert this to Angular' is a bit off because Angular runs on Typescript, which is a language built from javascript. So, yes you can do all this in Angular or rather using Typescript within an Angular app.
We're always here to help once you get some code written in an Angular app! But in general, we are here to help you were you get stuck in code and help you solve the problem. It's a bit more challenging to say 'yes it will work' without seeing how you implement it in your project and can't really guide or help you until we see how your angular components are written.
Short answer: Yeah, I think it can work. But it also depends how you implement this code into your Angular app.

Less CSS mixin guard clause not working as expected

I have a mixin that I've developed to allow for responsive padding and margins.
The idea is allow for any permutation - for example, I can declare just the #top, vertical sides with #vertical, or all (#all).
I first check to see if any individual properties have been declared, the vertical/horizontal, then all.
The code below DOESN'T work correctly. Here's the offending code:
& when not (#top = 0), (#right = 0), (#bottom = 0), (#left = 0) {
.MakeFluidGutter(#top; #right; #bottom; #left);
}
It fails to correctly work out that I've declared 3 individual properties.
I presume that the two other guard clauses beneath don't work either for the same reason.
Here's a quick fix:
& when (#top > 0), (#top < 0), (#right > 0), (#right < 0), (#bottom > 0), (#bottom < 0), (#left > 0), (#left < 0) {
.MakeFluidGutter(#top; #right; #bottom; #left);
}
Here's how I call it:
.FluidPadding(#right:1; #bottom:1; #left:1);
It's probably down to my interpretation but I know there are a couple of experts on here who will be able to guide me down the right path.
Talking of right paths - if there is a better way of achieving the .FluidGutter() functionality please let me know as I'm learning as I go.
Here's the complete code:
.FluidMargin(#top:0; #right:0; #bottom:0; #left:0; #vertical:0; #horizontal:0; #all:1) {
.FluidGutter(margin; #top; #right; #bottom; #left; #vertical; #horizontal; #all)
}
.FluidPadding(#top:0; #right:0; #bottom:0; #left:0; #vertical:0; #horizontal:0; #all:1) {
.FluidGutter(padding; #top; #right; #bottom; #left; #vertical; #horizontal; #all)
}
.FluidGutter(#property; #top; #right; #bottom; #left; #vertical; #horizontal; #all) when
(#property = margin),
(#property = padding) {
& when not (#top = 0), (#right = 0), (#bottom = 0), (#left = 0) {
.MakeFluidGutter(#top; #right; #bottom; #left);
}
& when (#top = 0) and (#right = 0) and (#bottom = 0) and (#left = 0) and not (#vertical = 0), not (#horizontal = 0) {
.MakeFluidGutter(#vertical; #horizontal; #vertical; #horizontal);
}
& when (#top = 0) and (#right = 0) and (#bottom = 0) and (#left = 0) and (#vertical = 0) and (#horizontal = 0) and not (#all = 0){
.MakeFluidGutter(#all; #all; #all; #all);
}
.MakeFluidGutter(#top; #right; #bottom; #left) {
.MakeGutter(#property; #arguments);
}
}
.MakeGutter(#property; #arguments) when
(#property = margin),
(#property = padding) {
.BuildGutter(#xSmallMargin);
& when (#smallMargin > #xSmallMargin) {
.SmallWindow({
.BuildGutter(#smallMargin);
});
}
& when (#mediumMargin > #smallMargin) {
.MediumWindow({
.BuildGutter(#mediumMargin);
});
}
& when (#largeMargin > #mediumMargin) {
.LargeWindow({
.BuildGutter(#largeMargin);
});
}
& when (#xLargeMargin > #largeMargin) {
.XLargeWindow({
.BuildGutter(#xLargeMargin);
});
}
.BuildVertGutter(#size) {
.-(top);
.-(right);
.-(bottom);
.-(left);
.-(#side) when not (##side = 0) {
#{property}-#{side}: (#size * ##side);
}
}
}

Resources