I'm using Codekit 2.1.8 to compile my LESS files. In my LESS files I have empty lines and I want to have them in compilied CSS file too, but Codekit seems to delete them. I can't find any options in Codekit related to this issue.
Example:
LESS file:
p {
font-size: 14px;
}
a {
color: red;
}
Compilied CSS file with Codekit:
p {
font-size: 14px;
}
a {
color: red;
}
When using the default command line or client side you can easily add your own plugins since v2. Less preserves /**/ comments.
Add in your LESS code for instance /*3*/ for 3 newlines.
Now write the plugin, call this file less-plugin-add-newlines.js:
var getCommentsProcessor = require("./comments-processor");
module.exports = {
install: function(less, pluginManager) {
var CommentsProcessor = getCommentsProcessor(less);
pluginManager.addPostProcessor(new CommentsProcessor());
}
};
Than write the comments-processor.js:
String.prototype.repeat = function( num )
{
return new Array( num + 1 ).join( this );
}
module.exports = function(less) {
function CommentProcessor(options) {
this.options = options || {};
};
CommentProcessor.prototype = {
process: function (css) {
var r = new RegExp("(\\/\\*)([0-9]+)(\\*\\/)","g");
return css.replace(r,function(m1,m2,m3){ return "\n".repeat(m3*1-1); });
}
};
return CommentProcessor;
};
less
p1 {
p:3;
}
/*3*/
p2 {
p:3;
}
/*4*/
p2 {
p:3;
}
The preceding will compile into when running lessc --plugin=less-plugin-add-newlines.js index.less:
p1 {
p: 3;
}
p2 {
p: 3;
}
p2 {
p: 3;
}
Related
I am using Ember even though I am making changes but when I run the ./watch its not producing the JavaScript file with new code - its annoying - I am making the manual change but that's not correct solution right? I made the change to the file even by opening in folder and manually updated the code on ember file - still its writing the old code in app.js file.
What could be the reason? I am using Web Pack to run ./watch and generate the app.js file.
Here is my Ember js code:
export default () => {
IMS.registerController("case.details.assignedinspector.edit", {
caseDetails: Ember.inject.controller('caseDetails'),
caseId: Ember.computed.alias('caseDetails.model.imscase.id'),
clearForm: function () {
$('.modal').modal('hide');
},
actions: {
close: function (id) {
$('.modal').modal('hide');
this.transitionToRoute('case.details');
},
async save() {
var scope = this;
//validating form
if ($("#edit-assignedinspector-form").validate()) {
var data = {
AssignedToInvestigators: Ember.get(scope, 'model.imscase.assignedToInvestigators'), //AssignedToInspectorId: $("#assignedInspectorSelect").chosen().val(),
CaseId: this.get('caseId')
};
try {
let response = await this.api('Case/UpdateAssignedInvestigators').post(data);
$('.modal').modal('hide');
toastr.success("Assigned Inspector Edit Saved.");
scope.transitionToRoute("case.details");
scope.get('caseDetails').refreshData();
scope.clearForm();
} catch (ex) {
toastr.error("Error saving Assigned Inspector.");
}
}
else {
toastr.warning("Please fix the form", "Validation failed");
}
},
didInsert: function () {
$('#edit-assignedinspector-modal').modal();
}
}
});
}
Here is how its generating the old code in app.js file:
save: function () {
var _save = _asyncToGenerator(
/*#__PURE__*/
regeneratorRuntime.mark(function _callee() {
var scope, data, response;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
scope = this; //validating form
if (!$("#edit-assignedinspector-form").validate()) {
_context.next = 19;
break;
}
data = {
AssignedToInspectorId: $("#assignedInspectorSelect").chosen().val(),
CaseId: this.get('caseId')
};
_context.prev = 3;
_context.next = 6;
return this.api('Case/UpdateAssignedInspector').post(data);
case 6:
response = _context.sent;
$('.modal').modal('hide');
toastr.success("Assigned Inspector Edit Saved.");
scope.transitionToRoute("case.details");
scope.get('caseDetails').refreshData();
scope.clearForm();
_context.next = 17;
break;
case 14:
_context.prev = 14;
_context.t0 = _context["catch"](3);
toastr.error("Error saving Assigned Inspector.");
case 17:
_context.next = 20;
break;
case 19:
toastr.warning("Please fix the form", "Validation failed");
case 20:
case "end":
return _context.stop();
}
}
}, _callee, this, [[3, 14]]);
}));
function save() {
return _save.apply(this, arguments);
}
return save;
}()
It is supposed to call Case/UpdateAssignedInvestigators instead its still calling the Case/UpdateAssignedInspector, which is incorrect.
I have following less:
#threshold:{
a:50;
b:200;
};
#themes:{
a:red;
b:blue;
};
.mymixin(#name,#color,#thrshld){
//do-something
}
each(#themes,{
.mymixin(#key,#value,#threshold[#key]);
});
By running the code, following error occurs:
RuntimeError: error evaluating function each: variable #key not found...
I'm using v3.9.0
How can I use Maps in each function?
You need to use the #map[$#property] syntax to evaluate the value of #map[#property]
.mymixin(#name, #color, #thrshld) {
.theme-#{name} {
color: #color;
width: #thrshld;
}
}
#threshold: {
a: 50;
b: 200;
};
#themes: {
a: red;
b: blue;
};
each(#themes, {
.mymixin(#key, #value, #threshold[$#key])
})
In an aurelia project I have several components that import additional stylesheets, e.g. from semantic-ui. After leaving the components page, the stylesheet is still active and not removed. Is it possible to 'unload' the stylesheets?
Update (2018-03-27):
I submitted a PR to enable this as an opt-in, you can keep track of it here: https://github.com/aurelia/templating-resources/pull/344
Original answer:
A word of warning, this is untested and aurelia-internals-hacky.
What you could do is override the default CSSViewEngineHooks and CSSResource classes to keep track of the style elements it injects, and then add an beforeUnbind hook to remove the styles again.. before unbind (right after detached)
Unfortunately the CSSResource class is not exported from aurelia-templating-resources so we need to go one layer deeper and overwrite the existing style loader plugins that returns instances of CSSResource.
Here's how:
First we grab the code from aurelia-templating-resources/src/css-resource.js, put it in our own src/css-resource.js/ts and make a few tweaks to it (don't think too much of the size, it's just a copy-paste with a few small tweaks, annotated with comments):
import {ViewResources, resource, ViewCompileInstruction} from 'aurelia-templating';
import {Loader} from 'aurelia-loader';
import {Container} from 'aurelia-dependency-injection';
import {relativeToFile} from 'aurelia-path';
import {DOM, FEATURE} from 'aurelia-pal';
let cssUrlMatcher = /url\((?!['"]data)([^)]+)\)/gi;
function fixupCSSUrls(address, css) {
if (typeof css !== 'string') {
throw new Error(`Failed loading required CSS file: ${address}`);
}
return css.replace(cssUrlMatcher, (match, p1) => {
let quote = p1.charAt(0);
if (quote === '\'' || quote === '"') {
p1 = p1.substr(1, p1.length - 2);
}
return 'url(\'' + relativeToFile(p1, address) + '\')';
});
}
class CSSResource {
constructor(address: string) {
this.address = address;
this._scoped = null;
this._global = false;
this._alreadyGloballyInjected = false;
}
initialize(container: Container, target: Function): void {
this._scoped = new target(this);
}
register(registry: ViewResources, name?: string): void {
if (name === 'scoped') {
registry.registerViewEngineHooks(this._scoped);
} else {
this._global = true;
}
}
load(container: Container): Promise<CSSResource> {
return container.get(Loader)
.loadText(this.address)
.catch(err => null)
.then(text => {
text = fixupCSSUrls(this.address, text);
this._scoped.css = text;
if (this._global) {
this._alreadyGloballyInjected = true;
// DOM.injectStyles(text); <- replace this
// this is one of the two possible moments where the style is injected
// _scoped is the CSSViewEngineHooks instance, and we handle the removal there
this._scoped.styleNode = DOM.injectStyles(text);
}
});
}
}
class CSSViewEngineHooks {
constructor(owner: CSSResource) {
this.owner = owner;
this.css = null;
}
beforeCompile(content: DocumentFragment, resources: ViewResources, instruction: ViewCompileInstruction): void {
if (instruction.targetShadowDOM) {
DOM.injectStyles(this.css, content, true);
} else if (FEATURE.scopedCSS) {
let styleNode = DOM.injectStyles(this.css, content, true);
styleNode.setAttribute('scoped', 'scoped');
} else if (this._global && !this.owner._alreadyGloballyInjected) {
// DOM.injectStyles(this.css); <- replace this
// save a reference to the node so we can easily remove it later
this.styleNode = DOM.injectStyles(this.css);
this.owner._alreadyGloballyInjected = true;
}
}
// this is the hook we add, here we remove the node again
beforeUnbind(): void {
if (this._global && this.owner._alreadyGloballyInjected) {
DOM.removeNode(this.styleNode);
this.owner._alreadyGloballyInjected = false;
}
}
}
export function _createCSSResource(address: string): Function {
#resource(new CSSResource(address))
class ViewCSS extends CSSViewEngineHooks {}
return ViewCSS;
}
Then, in our main.ts/js we do the same thing aurelia-templating-resources.js does, but with our own version.
So we do this after the call to aurelia.use.standardConfiguration() etc, to override the existing one
let viewEngine = config.container.get(ViewEngine);
let styleResourcePlugin = {
fetch(address) {
return { [address]: _createCSSResource(address) };
}
};
['.css', '.less', '.sass', '.scss', '.styl'].forEach(ext => viewEngine.addResourcePlugin(ext, styleResourcePlugin));
And that should pretty much do the trick.. :)
I have found a plugin to resolve the issue:
https://github.com/jbockle/aurelia-useable-style-loader
But for the latest Webpack webpack.config.js should be a little bit different than in a plugin readme.
You should load .css files this way:
use: [
{ loader: 'style-loader', options: { injectType: 'lazyStyleTag' } },
'css-loader'
]
Instead of this:
use: ['style-loader/useable', 'css-loader']
I have the following example:
var page = require('webpage').create(),
system = require('system');
if (system.args.length < 3) {
console.log('Usage: printheaderfooter.js URL filename');
phantom.exit(1);
} else {
var address = system.args[1];
var output = system.args[2];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = {
format: 'A4',
margin: "1cm"
footer: {
height: "1cm",
contents: phantom.callback(function(pageNum, numPages) {
if (pageNum == numPages) {
return "";
}
return "<h1 class='footer_style'>Footer" + pageNum + " / " + numPages + "</h1>";
})
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}
In the example above I use footer_style class that look likes in my css file the following:
.footer_style {
text-align:right;
}
But unfortunately that dosen't works. I'm trying to create pdf file such as follows:
./phantomjs rasterize.js index.html test.pdf
We know that classes do not work but inline styles do. What we can do is replace the class with the computed style.
Here is a function that will take a piece of html, create a temporary element in the body with the html, compute the style for each element with a class, add the computed style inline and return the new html.
function replaceClassWithStyle(html) {
return page.evaluate(function(html) {
var host = document.createElement('div');
host.innerHTML = html;
document.body.appendChild(host); // if not appended, values will be blank
var elements = host.getElementsByTagName('*');
for (var i in elements) {
if (elements[i].className) {
elements[i].setAttribute('style', window.getComputedStyle(elements[i], null).cssText);
}
}
document.body.removeChild(host);
return host.innerHTML;
}, html);
}
Then simply call this function in your footer:
page.paperSize = {
footer: {
contents: phantom.callback(function(pageNum, numPages) {
if (pageNum == numPages) {
return "";
}
return replaceClassWithStyle("<h1 class='footer_style'>Footer" + pageNum + " / " + numPages + "</h1>");
})
}
};
You will need to move all this inside page.open().
I tested it and the footer is aligned to the right.
I have an update to mak's excellent answer for PhantomJS 1.9.7.
This version fixes:
Circumvent bug which 'blank's the parent document (PhantomJS 1.9.7)
Style mixups when styles are nested (do depth-first traversal instead)
Also works when tags do not have classes
/**
* Place HTML in the parent document, convert CSS styles to fixed computed style declarations, and return HTML.
* (required for headers/footers, which exist outside of the HTML document, and have trouble getting styling otherwise)
*/
function replaceCssWithComputedStyle(html) {
return page.evaluate(function(html) {
var host = document.createElement('div');
host.setAttribute('style', 'display:none;'); // Silly hack, or PhantomJS will 'blank' the main document for some reason
host.innerHTML = html;
// Append to get styling of parent page
document.body.appendChild(host);
var elements = host.getElementsByTagName('*');
// Iterate in reverse order (depth first) so that styles do not impact eachother
for (var i = elements.length - 1; i >= 0; i--) {
elements[i].setAttribute('style', window.getComputedStyle(elements[i], null).cssText);
}
// Remove from parent page again, so we're clean
document.body.removeChild(host);
return host.innerHTML;
}, html);
}
From my past experience, phantomjs does not support styles in custom header/footer.
The only solution that I found is to apply an inline style like this :
var page = require('webpage').create(),
system = require('system');
if (system.args.length < 3) {
console.log('Usage: printheaderfooter.js URL filename');
phantom.exit(1);
} else {
var address = system.args[1];
var output = system.args[2];
page.viewportSize = { width: 600, height: 600 };
page.paperSize = {
format: 'A4',
margin: "1cm",
footer: {
height: "1cm",
contents: phantom.callback(function(pageNum, numPages) {
return "<h1 style='text-align:right'>Footer" + pageNum + " / " + numPages + "</h1>";
})
}
};
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
} else {
window.setTimeout(function () {
page.render(output);
phantom.exit();
}, 200);
}
});
}
Note : A comma is missing in your code after margin: "1cm"
I have a standalone Swing application and I'm using Groovy as programing language.
Trying to apply styles using CSS and searching for some tool for this purpose, I've found CSSBuilder.
The problem is that CSSBuilder comes integrated with Griffon framework, so I cannot use all of its features isolated from Griffon, such as 'cssClass' selector.
Therefore my question is simply: has anyone managed to do something like this?
Just wrote a quick test, and this seems to work:
#GrabResolver( name='codehaus', root='http://repository.codehaus.org' )
#Grab( 'org.codehaus.griffon:cssbuilder:0.4' )
import griffon.builder.css.*
import groovy.swing.SwingBuilder
import java.awt.BorderLayout as BL
def style = '''* {
background-color: red;
}
jbutton {
background-color: blue;
}
.active {
color: green ;
font-size: 50%;
}
jlabel {
color: pink ;
font-size: 200% ;
}'''
Class klass = javax.swing.JComponent
if( !AbstractSyntheticMetaMethods.hasBeenEnhanced(klass) ) {
AbstractSyntheticMetaMethods.enhance(klass,[
"getCssClass": {-> delegate.getClientProperty(ClarityConstants.CLIENT_PROPERTY_CLASS_KEY) },
"setCssClass": { String cssClass -> delegate.putClientProperty(ClarityConstants.CLIENT_PROPERTY_CLASS_KEY, cssClass) }
])
}
new SwingBuilder().edt {
int count = 0
def frame = frame( title:'CSS Test', size:[ 300, 300 ], show: true ) {
borderLayout()
textlabel = label(text:"Click the button!", constraints: BL.NORTH)
button(text:'Click Me',
cssClass: 'active',
actionPerformed: {count++; textlabel.text = "Clicked ${count} time(s)."; println "clicked"},
constraints:BL.SOUTH)
}
CSSDecorator.applyStyle( style, frame )
}
The meta-class enhancing code I took from the source of CSSBuilder