I understand that the target attribute of an <a> link cannot be specified by CSS. I would like to be able to generate external links in a Jekyll based markdown document with the following output:
the text
without resorting to something like this:
[the text](the url){:target"_blank" class="external"}
I don't want to hard-code the target in each link, because I might want to change it at some point, also it's noisy. So ideally I would have
[the text](the url){:class="external"}
...but then CSS cannot add the target="_blank".
So my idea would be a custom plugin that allows me to write
{% ext-link the-url the text %}
Does such a plugin exist? Are there better ways to achieve this?
When you need to do this on Github pagesand then cannot use plugins, you can do it with javascript :
// any link that is not part of the current domain is modified
(function() {
var links = document.links;
for (var i = 0, linksLength = links.length; i < linksLength; i++) {
// can also be
// links[i].hostname != 'subdomain.example.com'
if (links[i].hostname != window.location.hostname) {
links[i].target = '_blank';
links[i].className += ' externalLink';
}
}
})();
Inspired by this answer.
It seems writing a plugin is straight forward. This is what I have come up with:
module Jekyll
class ExtLinkTag < Liquid::Tag
#text = ''
#link = ''
def initialize(tag_name, markup, tokens)
if markup =~ /(.+)(\s+(https?:\S+))/i
#text = $1
#link = $3
end
super
end
def render(context)
output = super
"<a class='external' target='_blank' href='"+#link+"'>"+#text+"</a>"
end
end
end
Liquid::Template.register_tag('extlink', Jekyll::ExtLinkTag)
Example usage:
Exhibition at {% extlink Forum Stadtpark http://forum.mur.at %}.
HTML output:
<p>Exhibition at <a class="external" target="_blank" href="http://forum.mur.at">Forum Stadtpark</a>.</p>
There is a small Jekyll plugin to apply target="_blank", rel="nofollow", class names, and any other attributes of your choice to external links automatically:
Jekyll ExtLinks Plugin
A list of hosts to be skipped when applying rel can be configured if you want to keep some links untouched. This way, you don't have to mangle with Markdown anymore.
UPD: This plugin has been released to RubyGems now: jekyll-extlinks. Use gem install jekyll-extlinks to install it. Also available on GitHub.
My plugin can automatically force all external links to open in a new browser.
https://keith-mifsud.me/projects/jekyll-target-blank
And as of v1.1.0 you can also add optional extra CSS class names.
Related
I have multiple DIV elements on my page with the class "grid-item-container"
I want to make the background-color of each one different. I will set an array of 5 different colours that can be set.
There is a script available here that seems to do this: http://jsfiddle.net/VXG36/1/
$(document).ready(function() {
var randomColors = ["green","yellow","red","blue","orange","pink","cyan"];
$(".random").each(function(index) {
var len = randomColors.length;
var randomNum = Math.floor(Math.random()*len);
$(this).css("backgroundColor",randomColors[randomNum]);
//Removes color from array so it can't be used again
randomColors.splice(randomNum, 1);
});
});
I cannot however get it to run on my page. Is there something in this script that needs to be amended to make it Wordpress friendly?
Kind regards
Dave
You might wan't to wrap it in something like this:
jQuery(document).ready(function($) {
// Inside of this function, $() will work as an alias for jQuery()
// and other libraries also using $ will not be accessible under this shortcut
});
The jQuery library included with WordPress is set to the noConflict() mode (see wp-includes/js/jquery/jquery.js). This is to prevent compatibility problems with other JavaScript libraries that WordPress can link. Read more about it in Codex here.
Also, change $(.random) to $(.grid-item-container), this targets the class of your div.
I got error message when trying to run existing meteor project.
$meteor
=> Started proxy.
=> Started MongoDB.
=> Errors prevented startup:
While building the application:
client/coinmx.html:169: TRIPLE template tag is not allowed in an HTML attribute
...title="Totals: {{{get...
^
In Meteor 0.8, it's possible to return a Javascript object which is directly rendered into HTML attributes versus earlier versions, where you had to render it yourself.
Old version:
<input name={{name}} title={{title}}>
helpers:
Template.foo.name = "fooName";
Template.foo.title = "fooTitle";
New version:
<input {{attributes}}>
helpers:
Template.foo.attributes = {
name: "fooName",
title: "fooTitle"
};
All of these can be functions, and reactive, etc. Because the object is rendered directly into attributes, there is no need for you to SafeString some manually rendered content as before. This is the recommended way to go if need to render HTML attributes.
See also the following for how conditional attributes work under this scheme:
https://github.com/meteor/meteor/wiki/Using-Blaze#conditional-attributes-with-no-value-eg-checked-selected
The error is pretty much explanatory: you cannot use {{{something}}} inside a HTML attribute, you need to use {{something}} instead. Depending on what the something is (it's not known from your question as you didn't provide the code), that's either all you need to do, or you can achieve similar functionality by returning new Handlebars.SafeString("result") from your helper instead of just "result". However, if you do, you need to be super sure that the thing you'll return won't break the HTML structure.
Hugo's answer above gave me the missing piece I needed for the same issue-- triple stashes in 0.8 no longer supported. Here is an example that hopefully helps.
Where you might have had {{{resolve}}} in your template, you would now do:
<template name='thing'>
<ol>
{{#each all}}
{{resolve}}
{{/each}}
</ol>
<template>
The helper code then makes use of Spacebars.SafeString which looks to be preferred with Blaze:
Template.thing.helpers({
all: function () {
return Things.find();
},
resolve: function () {
var result = "<li>";
for (var i = 0; i < this.arrayOfClassNames.length; ++i)
result += <'div class='" + this.arrayOfClassNames[i] + "'></div>";
result += "</li>";
return new Spacebars.SafeString(result);
}
});
The key here is to return the 'new Spacebars.SafeString(result)' to wrap your HTML (which must be well formed).
I have made my own plugin.I am using tinymce with it.Now, to specify the css file for tinymce we use content_css inside tinymce.init, but in my case i dont want to specify the css file path in tinymce file itself but want it to be looked up in my plugin.js file. How can i do that?
Done.Thought of sharing the solution here. In my plugin's js file which i have called plugin.js i have written
tinymce.PluginManager.add('matheditor', function(editor, url) {
function TinyMCEAdapter(){
var pluginPath = '../editor.html',
editOptions = null,
editedElementId = null;
editor.settings.content_css = '../themes/tangerine/css/equationeditor.css';
}}
here the parameter matheditor is the name of my plugin.We set the content_css for tinymce with the line
editor.settings.content_css = '../themes/tangerine/css/equationeditor.css';`
Check out this tutorial: http://www.javascriptkit.com/javatutors/loadjavascriptcss.shtml
You call loadjscssfile function as soon as your plugin is loaded.
I was hoping anyone could give some input on this,
I'm creating a meteor app in which I would like to use bootstrap to creating the admin environment, but have the visitor facing side using custom css. When I add the bootstrap package to my app using meteor it's available on every page, is there a way to restrict the loading of bootstrap to routes that are in '/admin' ?
When you add bootstrap package it's not possible. You can, however, add bootstrap csses to public directory and then load them in a header subtemplate that will only be rendered when you're in the dashboard.
EDIT
But then how would you go about creating seperate head templates?
Easy:
<head>
...
{{> adminHeader}}
...
</head>
<template name="adminHeader">
{{#if adminPage}}
... // Put links to bootstrap here
{{/if}}
</template>
Template.adminHeader.adminPage = function() {
return Session.get('adminPage');
}
Meteor.router.add({
'/admin': function() {
Session.set('adminPage', true);
...
}
});
DISCLAIMER: I am unsure of a 'meteor way' to do this, so here is how I would do it with plain JS.
jQuery
$("link[href='bootstrap.css']").remove();
JS - Credit to javascriptkit
function removejscssfile(filename, filetype){
var targetelement=(filetype=="js")? "script" : (filetype=="css")? "link" : "none" //determine element type to create nodelist from
var targetattr=(filetype=="js")? "src" : (filetype=="css")? "href" : "none" //determine corresponding attribute to test for
var allsuspects=document.getElementsByTagName(targetelement)
for (var i=allsuspects.length; i>=0; i--){ //search backwards within nodelist for matching elements to remove
if (allsuspects[i] && allsuspects[i].getAttribute(targetattr)!=null && allsuspects[i].getAttribute(targetattr).indexOf(filename)!=-1)
allsuspects[i].parentNode.removeChild(allsuspects[i]) //remove element by calling parentNode.removeChild()
}
}
removejscssfile("bootstrap.css", "css")
However, doing that would complete remove it from the page. I am not sure whether meteor would then try to readd it when a user goes to another page. If that does not automatically get readded, then you have an issue of bootstrap not being included when someone goes from the admin section to the main site, which would break the look of the site.
The way I would get around that would be to disable and enable the stylesheets:
Meteor.autorun(function(){
if(Session.get('nobootstrap')){
$("link[href='bootstrap.css']").disabled = true;
}else{
$("link[href='bootstrap.css']").disabled = false;
}
});
There my be other bootstrap resources which may need to be removed, take a look at what your page is loading.
To use jQuery in the same way but for the javascript files, remember to change link to script and href to src
From my tests, Meteor does not automatically re-add the files once they have been removed so you would need to find some way of re-adding them dynamically if you want the same user to be able to go back and forth between the main site and the admin site. Or simply if the http referrer to the main site is from the admin, force reload the page and then the bootstrap resources will load and everything will look pretty.
P.s. make sure you get the href correct for the jQuery version
If somebody is interested in including any js/css files, I've written a helper for it:
if (Meteor.isClient) {
// dynamic js / css include helper from public folder
Handlebars.registerHelper("INCLUDE_FILES", function(files) {
if (files != undefined) {
var array = files.split(',');
array.forEach(function(entity){
var regex = /(?:\.([^.]+))?$/;
var extension = regex.exec(entity)[1];
if(extension == "js"){
$('head').append('<script src="' + entity + '" data-dynamicJsCss type="text/javascript" ></script>');
} else if (extension == "css"){
$('head').append('<link href="' + entity + '" data-dynamicJsCss type="text/css" rel="stylesheet" />');
};
});
}
});
Router.onStop(function(){
$("[data-dynamicJsCss]").remove();
});
}
Then simply use:
{{INCLUDE_FILES '/css/html5reset.css, /js/test.js'}}
in any of your loaded templates :)
I'm using the latest Drupal 7.2 core and I have no idea how to solve my problem. I'd like to collapse all nodes comments (there's lots of them) and expose them for the user when he presses 'show comments'. I know it has something to do with the fieldsets (or maybe I'm wrong), but where, what and how ?
Every helpful answer will be appreciated.
Thanks in advance.
I wrote a begging private message to one of the contributors and he posted a working solution for collapsible comments in D7 - http://drupal.org/node/94035#comment-4674734
So i tried a bunch of ways as suggested here.
The thing I ended up doing since I was trying to basically just put all the comments stuff into a collapsible fieldset is outlined here:
Go into the Content Type -> Manage Display.
Create an empty fieldset called something like Comments (You'll need fieldset/fieldcollection modules)
Once you have the group, grab the field_groupname for later use in code.
In your theme's template.php, or whereever you have the render arrays you'll have something like this to basically add the "comments" object into the group fieldset you just created.
function mytheme_preprocess_node(&$vars, $hook){
$tempField = null;
// Copy the comments / comment form into a variable.
$tempField = $vars['content']['comments'];
// Rename some of the labels, use the markup
$tempField['#title'] = "DMS URL";
$tempField['#field_name'] = "field_comments";
$tempField[0]['#markup'] = $vars['content']['comments'];
// Add it into the group (fieldset/group name you copied)
$vars['content']['group_commentsgroup']['field_comments'] = $tempField;
}
This will basically add your comments markup into an empty fieldset/group you created using node's manage display using fieldset/fieldcollection. Also, I was using ajax_comments for this.
This is more of a tip than an answer to your problem, but our website stopped using Drupal comments since they were too basic and moved to use the free service called Disqus
After a looong time of searching For Individual Collapsible comments I found a solution, where you can put your comment replies in an individual collapsible fieldset. :)
Below code in script.js
Include the js in .info file as scripts[] = js/script.js
(function($) {$(function() {
// Hurry up and hide the comments and its replies, if present. In most browsers, this
$('.indented').hide();
// The Comment section will be turned into a toggle to
// open/close the comments
$('.comment').addClass('closed').bind('click', function() {
var $self = $(this),
$form = $self.siblings('.indented'),
speed = 250; // speed of animation, change to suit, larger = slower
if ($self.hasClass('open')) {
$self.addClass('transition').removeClass('open');
$form.hide(speed, function() {
$self.addClass('closed').removeClass('transition');
});
}
else {
$self.addClass('transition').removeClass('closed');
$form.show(speed, function() {
$self.addClass('open').removeClass('transition');
});
}
});
}); })(jQuery);