Skip to content

Commit

Permalink
Merge pull request cdnjs#1563 from philipwalton/html-inspector
Browse files Browse the repository at this point in the history
Add version 0.4.1.
  • Loading branch information
ryankirkman committed Jul 16, 2013
2 parents 9b70597 + 93d87bf commit 46d1c5e
Show file tree
Hide file tree
Showing 6 changed files with 3,583 additions and 1 deletion.
117 changes: 117 additions & 0 deletions ajax/libs/html-inspector/0.4.1/html-inspector.best-practices.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
HTMLInspector.rules.add("inline-event-handlers", function(listener, reporter) {

listener.on('attribute', function(name, value) {
if (name.indexOf("on") === 0) {
reporter.warn(
"inline-event-handlers",
"An '" + name + "' attribute was found in the HTML. Use external scripts for event binding instead.",
this
)
}
})

})

HTMLInspector.rules.add(
"script-placement",
{
whitelist: []
},
function(listener, reporter, config) {

var elements = []
, whitelist = config.whitelist
, matches = this.utils.matches

function isWhitelisted(el) {
if (!whitelist) return false
if (typeof whitelist == "string") return matches(el, whitelist)
if (Array.isArray(whitelist)) {
return whitelist.length && whitelist.some(function(item) {
return matches(el, item)
})
}
return false
}

listener.on("element", function(name) {
elements.push(this)
})

listener.on("afterInspect", function() {
var el
// scripts at the end of the elements are safe
while (el = elements.pop()) {
if (el.nodeName.toLowerCase() != "script") break
}
elements.forEach(function(el) {
if (el.nodeName.toLowerCase() == "script") {
// scripts with the async or defer attributes are safe
if (el.async === true || el.defer === true) return
// at this point, if the script isn't whitelisted, throw an error
if (!isWhitelisted(el)) {
reporter.warn(
"script-placement",
"<script> elements should appear right before "
+ "the closing </body> tag for optimal performance.",
el
)
}
}
})
})
}
)

HTMLInspector.rules.add(
"unnecessary-elements",
{
isUnnecessary: function(element) {
var name = element.nodeName.toLowerCase()
, isUnsemantic = name == "div" || name == "span"
, isAttributed = element.attributes.length === 0
return isUnsemantic && isAttributed
}
},
function(listener, reporter, config) {
listener.on('element', function(name) {
if (config.isUnnecessary(this)) {
reporter.warn(
"unnecessary-elements",
"Do not use <div> or <span> elements without any attributes.",
this
)
}
}
)
})

HTMLInspector.rules.add(
"unused-classes",
{
whitelist: [
/^js\-/,
/^supports\-/,
/^language\-/,
/^lang\-/
]
},
function(listener, reporter, config) {

var css = HTMLInspector.modules.css
, classes = css.getClassSelectors()
, foundIn = this.utils.foundIn

listener.on("class", function(name) {
if (!foundIn(name, config.whitelist) && classes.indexOf(name) < 0) {
reporter.warn(
"unused-classes",
"The class '"
+ name
+ "' is used in the HTML but not found in any stylesheet.",
this
)
}
}
)
})
114 changes: 114 additions & 0 deletions ajax/libs/html-inspector/0.4.1/html-inspector.convention.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
;(function() {

// ============================================================
// There are several different BEM naming conventions that
// I'm aware of. To make things easier, I refer to the
// methodologies by the name of projects that utilize them.
//
// suit: https://github.com/necolas/suit
// -------------------------------------
// BlockName
// BlockName--modifierName
// BlockName-elementName
// BlockName-elementName--modifierName
//
// inuit: http://inuitcss.com/
// ---------------------------
// block-name
// block-name--modifier-name
// block-name__element-name
// block-name__element-name--modifier-name
//
// yandex: http://bem.info/
// ------------------------
// block-name
// block-name__elemement-name
// block-name_modifier_name
// block-name__element-name_modifier_name
//
// ============================================================

var methodologies = {
"suit": {
modifier: /^([A-Z][a-zA-Z]*(?:\-[a-zA-Z]+)?)\-\-[a-zA-Z]+$/,
element: /^([A-Z][a-zA-Z]*)\-[a-zA-Z]+$/
},
"inuit": {
modifier: /^((?:[a-z]+\-)*[a-z]+(?:__(?:[a-z]+\-)*[a-z]+)?)\-\-(?:[a-z]+\-)*[a-z]+$/,
element: /^((?:[a-z]+\-)*[a-z]+)__(?:[a-z]+\-)*[a-z]+$/
},
"yandex": {
modifier: /^((?:[a-z]+\-)*[a-z]+(?:__(?:[a-z]+\-)*[a-z]+)?)_(?:[a-z]+_)*[a-z]+$/,
element: /^((?:[a-z]+\-)*[a-z]+)__(?:[a-z]+\-)*[a-z]+$/
}
}

function getMethodology() {
if (typeof config.methodology == "string") {
return methodologies[config.methodology]
}
return config.methodology
}

var config = {

methodology: "suit",

getBlockName: function(elementOrModifier) {
var block
, methodology = getMethodology()
if (methodology.modifier.test(elementOrModifier))
return block = RegExp.$1
if (methodology.element.test(elementOrModifier))
return block = RegExp.$1
return block || false
},

isElement: function(cls) {
return getMethodology().element.test(cls)
},

isModifier: function(cls) {
return getMethodology().modifier.test(cls)
}
}

HTMLInspector.rules.add(
"bem-conventions",
config,
function(listener, reporter, config) {

var parents = this.utils.parents
, matches = this.utils.matches

listener.on('class', function(name) {
if (config.isElement(name)) {
// check the ancestors for the block class
var ancestorIsBlock = parents(this).some(function(el) {
return matches(el, "." + config.getBlockName(name))
})
if (!ancestorIsBlock) {
reporter.warn(
"bem-conventions",
"The BEM element '" + name
+ "' must be a descendent of '" + config.getBlockName(name)
+ "'.",
this
)
}
}
if (config.isModifier(name)) {
if (!matches(this, "." + config.getBlockName(name))) {
reporter.warn(
"bem-conventions",
"The BEM modifier class '" + name
+ "' was found without the unmodified class '" + config.getBlockName(name)
+ "'.",
this
)
}
}
}
)
})
}())
Loading

0 comments on commit 46d1c5e

Please sign in to comment.