Commit 4a2f4fa2 authored by azul's avatar azul

cleanup: custom javascript and stylesheet handling

We use the assets pipeline for js and css for a while now.
We also moved away from assets as_needed by specific controllers.
All the js and all the css are send all the time to allow for better caching.

Remove the remains of the per controller asset handling
parent 9d7c5a1c
......@@ -2,6 +2,7 @@ Javascripts
==============================================
Javascript are served using the Sprockets gem for asset pipelining.
We load all scripts by including application.js on all pages.
About these scripts
----------------------------------------------
......@@ -20,19 +21,6 @@ app/javascripts/prototype.js
scriptaculous effects for prototype that we also use.
Using scripts
----------------------------------------------
We currently load all scripts on all pages (e.g. there is nothing in
as_needed). If you want an 'as_needed' script that is only loaded for a
particular controller:
class MyController < ApplicationController
javascript :tasks, :wiki
javascript :extra, :action => :index
end
Stylesheets
==============================================
......
//= require ./shims/classList.js
/*
* classList.js: Cross-browser full element.classList implementation.
* 1.2.20171210
*
* By Eli Grey, http://eligrey.com
* License: Dedicated to the public domain.
* See https://github.com/eligrey/classList.js/blob/master/LICENSE.md
*/
/*global self, document, DOMException */
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js */
if ("document" in self) {
// Full polyfill for browsers with no classList support
// Including IE < Edge missing SVGElement.classList
if (
!("classList" in document.createElement("_"))
|| document.createElementNS
&& !("classList" in document.createElementNS("http://www.w3.org/2000/svg","g"))
) {
(function (view) {
"use strict";
if (!('Element' in view)) return;
var
classListProp = "classList"
, protoProp = "prototype"
, elemCtrProto = view.Element[protoProp]
, objCtr = Object
, strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
}
, arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0
, len = this.length
;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
, DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
}
, checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR"
, "The token must not be empty."
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR"
, "The token must not contain space characters."
);
}
return arrIndexOf.call(classList, token);
}
, ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.getAttribute("class") || "")
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
, i = 0
, len = classes.length
;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.setAttribute("class", this.toString());
};
}
, classListProto = ClassList[protoProp] = []
, classListGetter = function () {
return new ClassList(this);
}
;
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
return ~checkTokenAndGetIndex(this, token + "");
};
classListProto.add = function () {
var
tokens = arguments
, i = 0
, l = tokens.length
, token
, updated = false
;
do {
token = tokens[i] + "";
if (!~checkTokenAndGetIndex(this, token)) {
this.push(token);
updated = true;
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.remove = function () {
var
tokens = arguments
, i = 0
, l = tokens.length
, token
, updated = false
, index
;
do {
token = tokens[i] + "";
index = checkTokenAndGetIndex(this, token);
while (~index) {
this.splice(index, 1);
updated = true;
index = checkTokenAndGetIndex(this, token);
}
}
while (++i < l);
if (updated) {
this._updateClassName();
}
};
classListProto.toggle = function (token, force) {
var
result = this.contains(token)
, method = result ?
force !== true && "remove"
:
force !== false && "add"
;
if (method) {
this[method](token);
}
if (force === true || force === false) {
return force;
} else {
return !result;
}
};
classListProto.replace = function (token, replacement_token) {
var index = checkTokenAndGetIndex(token + "");
if (~index) {
this.splice(index, 1, replacement_token);
this._updateClassName();
}
}
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter
, enumerable: true
, configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
// adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
// modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
if (ex.number === undefined || ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
}
// There is full or partial native classList support, so just check if we need
// to normalize the add/remove and toggle APIs.
(function () {
"use strict";
var testElement = document.createElement("_");
testElement.classList.add("c1", "c2");
// Polyfill for IE 10/11 and Firefox <26, where classList.add and
// classList.remove exist but support only one argument at a time.
if (!testElement.classList.contains("c2")) {
var createMethod = function(method) {
var original = DOMTokenList.prototype[method];
DOMTokenList.prototype[method] = function(token) {
var i, len = arguments.length;
for (i = 0; i < len; i++) {
token = arguments[i];
original.call(this, token);
}
};
};
createMethod('add');
createMethod('remove');
}
testElement.classList.toggle("c3", false);
// Polyfill for IE 10 and Firefox <24, where classList.toggle does not
// support the second argument.
if (testElement.classList.contains("c3")) {
var _toggle = DOMTokenList.prototype.toggle;
DOMTokenList.prototype.toggle = function(token, force) {
if (1 in arguments && !this.contains(token) === !force) {
return force;
} else {
return _toggle.call(this, token);
}
};
}
// replace() polyfill
if (!("replace" in document.createElement("_").classList)) {
DOMTokenList.prototype.replace = function (token, replacement_token) {
var
tokens = this.toString().split(" ")
, index = tokens.indexOf(token + "")
;
if (~index) {
tokens = tokens.slice(index);
this.remove.apply(this, tokens);
this.add(replacement_token);
this.add.apply(this, tokens.slice(1));
}
}
}
testElement = null;
}());
}
\ No newline at end of file
......@@ -11,9 +11,6 @@ class ApplicationController < ActionController::Base
include_helpers 'app/helpers/common/*/*.rb'
helper :application, :modalbox
class_attribute :stylesheets, instance_reader: false, instance_writer: false
class_attribute :javascripts, instance_reader: false, instance_writer: false
protected
# this is used by the code that is included for both controllers and helpers.
......@@ -52,58 +49,4 @@ class ApplicationController < ActionController::Base
opts[:port] = request.port_string.sub(':', '') if request.port_string.present?
opts
end
##
## CLASS METHODS
##
# We currently include all stylesheets in screen.css as it's cached,
# hardly expires and the optional stylesheets do not add much weight
# anyway.
#
# Still keeping this here though in case we need it again.
#
# rather than include every stylesheet in every request,
# we used to only include some stylesheets "as needed".
# A controller can set a custom stylesheet using 'stylesheet'
# in the class definition:
#
# for example:
#
# stylesheet 'gallery', 'images'
# stylesheet 'page_creation', :action => :create
#
# They'll be accessible in the class_attribute stylesheets
#
# as needed stylesheets are kept in public/stylesheets/as_needed
#
def self.stylesheet(*css_files)
self.stylesheets = merge_requirements(stylesheets, *css_files)
end
# We currently include all javascript in application.js as it's cached,
# hardly expires and the optional javascripts do not add much weight
# anyway.
#
# Still keeping this here though in case we need it again.
#
# let controllers require extra javascript
# for example:
#
# javascript 'wiki_edit', :action => :edit
#
# They'll be accessible in the class_attribute javascripts
#
def self.javascript(*js_files)
self.javascripts = merge_requirements(javascripts, *js_files)
end
def self.merge_requirements(current, *new_files)
current ||= {}
options = new_files.extract_options!
index = options[:action] || :all
value = current[index] || []
value += new_files
current.merge index => value.uniq
end
end
......@@ -23,38 +23,6 @@ module Common::Ui::LayoutHelper
end
end
##
## STYLESHEET
##
# as needed stylesheets:
# rather than include every stylesheet in every request, some stylesheets are
# only included if they are needed. See Application#stylesheet()
def optional_stylesheets
stylesheet = controller.class.stylesheets || {}
[stylesheet[:all], @stylesheet, stylesheet[params[:action].to_sym]].flatten.compact.collect { |i| "as_needed/#{i}" }
end
# crabgrass_stylesheets()
# this is the main helper that is in charge of returning all the needed style
# elements for HTML>HEAD.
def crabgrass_stylesheets
lines = []
lines << stylesheet_link_tag(current_theme.stylesheet_url('screen'))
lines << stylesheet_link_tag('icon_png')
lines << optional_stylesheets.collect do |sheet|
stylesheet_link_tag(current_theme.stylesheet_url(sheet))
end
# we currently do not ship the right to left css
# if language_direction == "rtl"
# lines << stylesheet_link_tag( current_theme.stylesheet_url('rtl') )
# end
lines.join("\n").html_safe
end
def favicon_link
if current_theme[:favicon_png] and current_theme[:favicon_ico]
format('<link rel="shortcut icon" href="%s" type="image/x-icon" /><link rel="icon" href="%s" type="image/x-icon" />', current_theme.url(:favicon_ico), current_theme.url(:favicon_png))
......@@ -63,60 +31,6 @@ module Common::Ui::LayoutHelper
end.html_safe
end
##
## JAVASCRIPT
##
SPROCKETS_PREFIX = '/static/'.freeze
#
# Includes the correct javascript tags for the current request.
# See ApplicationController#javascript for details.
#
def javascript_include_tags
scripts = controller.class.javascripts || {}
files = [:application] # asset pipeline js
files += [scripts[:all], scripts[params[:action].to_sym]].flatten.compact.collect { |i| "as_needed/#{i}" }
includes = []
files.each do |file|
includes << javascript_include_tag(file.to_s)
end
includes
end
def crabgrass_javascripts
lines = javascript_include_tags
# run firebug lite in dev mode for ie
if Rails.env == 'development'
lines << '<!--[if IE]>'
lines << "<script type='text/javascript' src='http://getfirebug.com/firebug-lite-beta.js'></script>"
lines << '<![endif]-->'
end
lines << '<!--[if IE]>'
lines << javascript_include_tag('shims')
lines << '<![endif]-->'
lines << '<script type="text/javascript">'
lines << localize_modalbox_strings
# inline script code
if content_for?(:script)
lines << content_for(:script)
end
lines << '</script>'
# Autocomplete caches results in sessionStorage. After logging out, the session storage should be cleared.
unless logged_in?
lines.push('<script type="text/javascript">if(sessionStorage.length > 0) sessionStorage.clear();</script>')
end
lines.join("\n").html_safe
end
##
## COLUMN SPANS
##
......
......@@ -26,19 +26,3 @@
#center .login_form {
margin: 0 auto;
}
// welcome screen
// this does not need to be universal, and perhaps should be moved to as_needed
//
//#welcome {
// #message {
// float: left;
// text-align: right;
// max-width: 30em;
// margin-right: 2em;
// }
// #login {
// float: left;
// }
//}
......@@ -5,17 +5,29 @@
%meta(charset="UTF-8")
%meta(name="referrer" content="same-origin")
= favicon_link
/ begin styling
= crabgrass_stylesheets
= stylesheet_link_tag(current_theme.stylesheet_url('screen'))
= stylesheet_link_tag('icon_png')
/ end styling
/ begin scripts
= crabgrass_javascripts
/ end scripts
= javascript_include_tag :application
:javascript
#{ localize_modalbox_strings }
// Autocomplete caches results in sessionStorage.
// After logging out, the session storage should be cleared.
#{ "if(sessionStorage.length > 0) sessionStorage.clear();" unless logged_in? }
- if content_for?(:dom_loaded)
:javascript
document.observe("dom:loaded",function(){
#{content_for(:dom_loaded)}
});
/ end scripts
= csrf_meta_tag
- if context_banner_style || @content_for_style
:css
......
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
<title><%= @page.title %> - Slideshow</title>
<%= javascript_include_tag :defaults %>
<%= stylesheet_link_tag 'as_needed/gallery_slideshow' %>
</head>
<body>
<%= render :partial => 'gallery/slideshow_navigation' %>
<div id="content">
</div>
<div id="next_image" style="display:none">
<%= yield %>
</div>
<%= javascript_tag("show_next_image();") %>
</body>
</html>
require 'test_helper'
class ApplicationControllerTest < ActiveSupport::TestCase
test 'can set stylesheet' do
class SimpleController < ApplicationController; end
SimpleController.stylesheet :test
assert_equal hash_for_all(:test), SimpleController.stylesheets
assert_nil ApplicationController.stylesheets
end
test 'can set javascript' do
class SimpleController < ApplicationController; end
SimpleController.javascript :test
assert_equal hash_for_all(:test), SimpleController.javascripts
assert_nil ApplicationController.javascripts
end
test 'stylesheets do not mess with super class' do
class BaseController < ApplicationController; end
class SubController < BaseController; end
BaseController.stylesheet :base
SubController.stylesheet :sub
assert_equal hash_for_all(:base, :sub), SubController.stylesheets
assert_equal hash_for_all(:base), BaseController.stylesheets
end
test 'subclasses do not add duplicates' do
class BaseController < ApplicationController; end
class SubController < BaseController; end
BaseController.stylesheet :base
SubController.stylesheet :sub, :base
assert_equal hash_for_all(:base, :sub), SubController.stylesheets
assert_equal hash_for_all(:base), BaseController.stylesheets
end
def hash_for_all(*values)
{ all: values }
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment