AngularJS directive to format a text with paragraphs and new lines
If you are using Angular and want something like Rails' simple_format
which HTML-formats a plain-text input into paragraphs and line breaks, this directive is for you.
Any HTML fragments inside that text will still be escaped properly.
Use it like this, where your text
attribute specifies something available in your current scope:
<simple-format text="email.message"></simple-format>
This is the directive, in CoffeeScript syntax:
@app.directive 'simpleFor...
Bootstrap 4 is coming
What's new
- Moved from Less to Sass. Bootstrap now compiles faster than ever thanks to Libsass, and we join an increasingly large community of Sass developers.
-
Improved grid system. We’ve added a new grid tier to better target mobile devices and completely overhauled our semantic mixins.
Opt-in flexbox support is here. The future is now—switch a boolean variable and recompile your CSS to take advantage of a flexbox-based grid system and components. - Dropped wells, thumbnails, and panels for cards. Cards are a brand new co...
Testing focus/blur events with Cucumber
This is a problem when using Selenium with Firefox. We recommend using ChromeDriver for your Selenium tests.
This setup allows to test focus/blur events in Cucumber tests (using Selenium). For background information, see How to solve Selenium focus issues.
Cucumber step definition:
# This step is needed because in Selenium tests, blur events are not triggered
# when the browser has no focus.
When /^I unfocus the "(.*?)" field to trigger ja...
Force absolute URLs in views throughout a response
This is more tricky than it should be because url_for
, asset_path
, etc. all rely on different mechanisms.
Anyway, you can use the attached trait like this:
class ExampleController < ApplicationController
does 'host_enforcement', :for => 'some_action'
end
Short explanation:
-
asset_host
is used for links to stylesheets and javascripts -
asset_host
belongs toActionController::Base
-- changes are persistent and will not be reset after a request -
rewrite_options
is used by the..._path
methods in the views
^...
Spreewald: Content-Disposition not set when testing a download's filename
Precondition
- You are not using javascript tests
- The file is served from a public folder (not via controller)
Problem description
If you deliver files from a public folder it might be that the Content-Disposition
header is not set. That's why the following spreewald step might raise an error:
Then I should get a download with filename "..."
expected: /filename="some.pdf"$/
got: nil (using =~) (RSpec::Expectations::ExpectationNotMetError)
Solution
One solution...
Clean up application servers when deploying
Our development process makes us deploy very often. As the number of releases grows, junk clogs up the hard drive of our application servers:
- Old release code
- Old
tmp
folders with compiled view templates etc. - Precompiled assets (Javascripts, images...) that no longer exist. When using the asset pipeline, Capistrano will symlink the
public/assets
directory toshared/assets
. This is cool since we can still serve previous assets after a new release, in the window where browser caches might still have references to old assets. But i...
Drag'n'drop in trees: I went to town
For my Gem Session project Holly I ran the Ironman of drag'n'drop implementations:
- Dragging in nested lists
- User-definable order of items
- Complicated item elements with super-custom CSS and other Javascript functionality
- Items that can be both leaves and containers of other items
- has_ancestry on the server side
Things I learned:
- Be ready to write a lot of CSS. You need to indicate what is being dragged, where it will be dropped, if it is dropped above, below o...
Pre-releasing a Ruby gem
When a Ruby version gem has a letter in its version number, it is considered a pre-release:
1.0.0.rc1
2.3.0.alpha2
3.0.0.beta3
4.0.0.pre.rc2
Even if a pre-release gem has the highest version number, it is never installed unless the user explictily requested the version:
gem install foobar --version="=2.3.0.alpha2"
Also bundle update
will never update a stable version to a pre-release version unless the user explicitly requests it in the Gemfile
:
gem 'foobar', '=2.3.0.alpha2'
A note on Semanti...
CSS: How to force background images to scale to the container, ignoring aspect ratio
You can scale background images in CSS to the container size using background-size
(Demo).
Commonly, we use contain
or cover
because we want to preserve the image's aspect ratio.
If you do not want to do that, simply provide scaling values for X and Y:
background-size: 100% 100%
(a simple 100%
would mean 100% auto
and respect the image's aspect ratio)
SVGs with a viewBox will force their aspect ratio
The above may not work for you when ...
Rails 3: Make "link_to :remote => true" replace HTML elements with jQuery
In Rails 2, you could use link_to_remote ... :update => 'id'
to automatically replace the content of $('#id')
.
To do the same in Rails 3, include usual rails-ujs JavaScript, and put this into your application.js
:
$(function() {
$('[data-remote][data-replace]')
.data('type', 'html')
.live('ajax:success', function(event, data) {
var $this = $(this);
$($this.data('replace')).html(data);
$this.trigger('ajax:replaced');...
Clicking issues with chromedriver
ChromeDriver clicking works by simulating a mouse click in the middle of the element's first client rect (or bounding client rect if it doesn't have a first client rect). (Clicking issues)
So if you are trying to click on an element, chromedriver
tries to click at the position where it first finds that element.
This can lead to some problems and unexpected behavior like:
-
Element is not clickable at point ...
erros - Another element which is now located at...
How to build a fully custom TinyMCE 5 dialog
TinyMCE is a WYSIWYG editor which is quite customizable.
- Add a custom button to the tinyMCE toolbar and tell tinyMCE to open a dialog with the route to your dialog's view.
tinymce.init({
// ...
toolbar: 'myCustomButton',
setup: function(editor) {
editor.ui.registry.addButton('myCustom Button', {
...
Make jQuery.animate run smoother with almost no code changes
jQuery comes with .animate()
that lets you transition some CSS selectors:
function floatIn($element) {
$element.css({ 'opacity': 0, 'margin-top': 200px });
$element.animate({ 'opacity': 1, 'margin-top': 0 }, { duration: 500 });
}
The animation is implemented using setInterval
and Javascript. This works great, but it's not as smooth as a CSS transition.
Fortunately the animate
API can be mapped almo...
Cucumber: Wait until CKEditor is loaded
I had to deal with JavaScript Undefined Error
while accessing a specific CKEditor instance to fill in text.
Ensure everything is loaded with
patiently do
page.execute_script("return isCkeditorLoaded('#{selector}');").should be_true
end
Example
The fill in text
snippet for Cucumber:
When /^I fill in the "([^\"]+)" WYSIWYG editor with:$/ do |selector, html|
patiently do
page.execute_script("return isCkeditorLoaded('#{selector}');").should be_true
end
html.gsub!(/\n+/, "") # otherwise: unterminated string lit...
Bookmarklet to generate a commit message with Pivotal Tracker story ID and title
For clarity and traceability, your commit messages should include the ID and title of the Pivotal Tracker story you're working on. For example:
[#12345] Add Google Maps to user profiles
Optional further commit messages in the body
Also see Howto: Write a proper git commit message
To quickly generate such commit messages, add a new link "Commit" to your bookmarks and use the following Javascript as the link URL:
javascript:(function() { ...
How to open a new tab with Selenium
Until recently, you could open a new tab via window.open
when using execute_script
in Selenium tests. It no longer works in Chrome (will show a "popup blocked" notification).
This is because browsers usually block window.open
unless the user interacted with an element for security reasons. I am not sure why it did work via Selenium before.
Here is an approach that will insert a link into the page, and have Selenium click it:
path = "/your/path/here"
id = "helper_#{SecureRandom.hex(8)}"
execute_script <<-JAVASCRIPT
...
Looping through iterators in Coffeescript
Some modern Javascript APIs return iterators instead of arrays.
In plain Javascript you can loop through an iterator using
for...of
:
var iterator = ...;
for (var value of iterator) {
console.log(value);
}
While there is a for...of
construct in Coffeescript, it iterates through property/value pairs and **...
Check that an element is hidden via CSS with Spreewald
If you have content inside a page that is hidden by CSS, the following will work with Selenium, but not when using the Rack::Test driver. The Selenium driver correctly only considers text that is actually visible to a user.
Then I should not see "foobear"
This is because the Rack::Test driver does not know if an element is visible, and only looks at the DOM.
Spreewald offers steps to check that an element is hidden by CSS:
Then "foo" should be hidden
You can also check that an el...
A few recent CSS properties
-
Feature Queries (Edge 12+): Similar to @media queries, @supports blocks can be scoped to browsers that support a given declaration. There is
CSS.supports()
to do the equivalent in Javascript. -
backdrop-filter
(Edge 17+, but not FF): Applying filters to what is visible through an element. -
[
touch-action
](https://d...
Bookmarklet to generate a Pivotal Tracker story from Zammad Ticket
This is a bookmarklet you can add to Chrome or Firefox which will allow you to create a story in Pivotal Tracker from a Zammad ticket. This might come in handy when creating stories for SWAT Teams.
But first you will have to set two variables in the script below:
-
pt_project_id
: the ID of the Pivotal Tracker Project you want to add stories to. This can be found as part of the URL of the project (https://www.pivotaltracker.com/n/projects/<pt_project_id>
) -
pt_token
: the Pivotal Tracker token used for authentication. Can be found in y...
IE7 not properly redrawing elements with position: relative
If you manipulate the DOM with JavaScript and your page contains nested elements with position: relative
, chances are Internet Explorer 7 will not properly move to the right position.
I have not found a fool-proof workaround, but these are options that have worked for me:
- Try to lose some
position: relative
attributes, so they do not nest. This is often impossible, though. - Force the correct redrawing of the elements using JavaScript. Adding a bogus class (
$(element).addClass('touch')
) seems to suffice. - Try to give the off...
IIFEs in Coffeescript
In JavaScript we often use Immediately Invoked Function Expessions (or IIFEs) to prevent local variables from bleeding into an outside scope:
(function() {
var foo = "value"; // foo is scoped to this IIFE
})();
In Coffeescript an IIFE looks like this:
(->
foo = "value" # foo is scoped to this IIFE
)()
There is also a shorthand syntax with do
:
do ->
foo = "value" # foo is scoped to this IIFE
You can also use do
with arguments t...
Webpack: Automatically generating an icon font from .svg files
Over the years we have tried several solution to have vector icons in our applications. There are many ways to achieve this, from SVGs inlined into the HTML, SVGs inlined in CSS, JavaScript-based solutions, to icon fonts.
Out of all these options, the tried and true icon font seems to have the most advantages, since
- icon fonts are supported everywhere
- they perform well and require no JavaScript at all
- their icons align nicely with text
- their icons automatically inherit color and size of the surrounding text
The big issue used to b...
Skip Selenium scenarios in a Cucumber run
Cucumber scenarios that are tagged with @javascript
so they run with Selenium are very slow. You might not want to run them every time.
In order to skip all Selenium scenarios, call Cucumber like this:
cucumber --tags ~@javascript
Note that you should still run all the scenarios, including the Selenium ones, before you push a change.