feat(grunt): Add demo grunt task
This commit is contained in:
@@ -8,6 +8,7 @@ lib-cov
|
||||
*.gz
|
||||
*.swp
|
||||
*.swo
|
||||
.DS_Store
|
||||
|
||||
pids
|
||||
logs
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
before_script:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm install --quiet -g grunt@0.3.x testacular@0.2.x
|
||||
- npm install --quiet -g grunt-cli testacular
|
||||
- npm install
|
||||
|
||||
script: grunt
|
||||
@@ -1,3 +1,6 @@
|
||||
var fs = require('fs');
|
||||
var markdown = require('node-markdown').Markdown;
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
// Project configuration.
|
||||
@@ -7,7 +10,7 @@ module.exports = function(grunt) {
|
||||
banner: 'angular.module("ui.bootstrap", [<%= modules %>]);'
|
||||
},
|
||||
lint: {
|
||||
files: ['grunt.js', 'src/**/*.js']
|
||||
files: ['grunt.js','src/**/*.js']
|
||||
},
|
||||
watch: {
|
||||
files: '<config:lint.files>',
|
||||
@@ -16,7 +19,7 @@ module.exports = function(grunt) {
|
||||
concat: {
|
||||
dist: {
|
||||
src: ['<banner>', 'src/*/*.js'],
|
||||
dest: 'dist/angular-ui-bootstrap.js'
|
||||
dest: 'dist/ui-bootstrap.js'
|
||||
}
|
||||
},
|
||||
html2js: {
|
||||
@@ -39,20 +42,58 @@ module.exports = function(grunt) {
|
||||
//register before and after test tasks so we've don't have to change cli options on the goole's CI server
|
||||
grunt.registerTask('before-test', 'lint html2js');
|
||||
grunt.registerTask('after-test', 'find-modules concat');
|
||||
grunt.registerTask('demo', 'before-test after-test build-demo');
|
||||
|
||||
// Default task.
|
||||
grunt.registerTask('default', 'before-test test after-test');
|
||||
grunt.registerTask('default', 'before-test test after-test demo');
|
||||
|
||||
//Common ui.bootstrap module containing all modules
|
||||
grunt.registerTask('find-modules', 'Generate ui.bootstrap module depending on all existing directives', function() {
|
||||
var modules = [];
|
||||
grunt.file.expandDirs('src/*').forEach(function(dir) {
|
||||
var moduleName = dir.split("/")[1];
|
||||
modules.push('"ui.bootstrap.' + moduleName + '"');
|
||||
var modules = grunt.file.expandDirs('src/*').map(function(dir) {
|
||||
return '"ui.bootstrap.' + dir.split("/")[1] + '"';
|
||||
});
|
||||
grunt.config('modules', modules);
|
||||
});
|
||||
|
||||
grunt.registerTask('build-demo', 'Create grunt demo.html from every module\'s files', function() {
|
||||
this.requires('find-modules concat html2js');
|
||||
|
||||
var modules = grunt.file.expandDirs('src/*').map(function(dir) {
|
||||
var moduleName = dir.split("/")[1];
|
||||
if (fs.existsSync(dir + "docs")) {
|
||||
return {
|
||||
name: moduleName,
|
||||
js: grunt.file.expand(dir + "docs/*.js").map(grunt.file.read).join(''),
|
||||
html: grunt.file.expand(dir + "docs/*.html").map(grunt.file.read).join(''),
|
||||
description: grunt.file.expand(dir + "docs/*.md").map(grunt.file.read).map(markdown).join('')
|
||||
};
|
||||
}
|
||||
return {
|
||||
name: moduleName,
|
||||
js: moduleName,
|
||||
html: moduleName,
|
||||
description: moduleName
|
||||
};
|
||||
});
|
||||
|
||||
var templateFiles = grunt.file.expand("template/**/*.html.js");
|
||||
|
||||
grunt.file.write(
|
||||
'dist/demo.html',
|
||||
grunt.template.process(grunt.file.read('misc/demo-template.html'), {
|
||||
modules: modules,
|
||||
templateModules: templateFiles.map(function(fileName) {
|
||||
return "'"+fileName.substr(0, fileName.length - 3)+"'";
|
||||
}),
|
||||
templates: templateFiles.map(grunt.file.read).join('')
|
||||
})
|
||||
);
|
||||
|
||||
grunt.file.expand('misc/demo-assets/*').forEach(function(path) {
|
||||
grunt.file.copy(path, 'dist/assets/' + path.replace('misc/demo-assets/',''));
|
||||
});
|
||||
});
|
||||
|
||||
//Html templates to $templateCache for tests
|
||||
grunt.registerMultiTask('html2js', 'Generate js versions of html template', function() {
|
||||
//Put templates on ng's run function so they are global
|
||||
@@ -60,14 +101,14 @@ module.exports = function(grunt) {
|
||||
' $templateCache.put("<%= file %>",\n "<%= content %>");\n' +
|
||||
'});\n';
|
||||
var files = grunt._watch_changed_files || grunt.file.expand(this.data);
|
||||
|
||||
|
||||
function escapeContent(content) {
|
||||
return content.replace(/"/g, '\\"').replace(/\n/g, '" +\n "').replace(/\r/g, '');
|
||||
}
|
||||
files.forEach(function(file) {
|
||||
grunt.file.write(file + ".js", grunt.template.process(TPL, {
|
||||
file: file,
|
||||
content: escapeContent(grunt.file.read(file))
|
||||
file: file,
|
||||
content: escapeContent(grunt.file.read(file))
|
||||
}));
|
||||
});
|
||||
});
|
||||
@@ -78,8 +119,8 @@ module.exports = function(grunt) {
|
||||
var args = [command].concat(options);
|
||||
var done = grunt.task.current.async();
|
||||
var child = grunt.utils.spawn({
|
||||
cmd: testacularCmd,
|
||||
args: args
|
||||
cmd: testacularCmd,
|
||||
args: args
|
||||
}, function(err, result, code) {
|
||||
if (code) {
|
||||
done(false);
|
||||
@@ -116,4 +157,4 @@ module.exports = function(grunt) {
|
||||
var options = ['--no-single-run', '--auto-watch'].concat(this.args);
|
||||
runTestacular('start', options);
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
Vendored
+6039
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Generic language patterns
|
||||
*
|
||||
* @author Craig Campbell
|
||||
* @version 1.0.9
|
||||
*/
|
||||
Rainbow.extend([
|
||||
{
|
||||
'matches': {
|
||||
1: {
|
||||
'name': 'keyword.operator',
|
||||
'pattern': /\=/g
|
||||
},
|
||||
2: {
|
||||
'name': 'string',
|
||||
'matches': {
|
||||
'name': 'constant.character.escape',
|
||||
'pattern': /\\('|"){1}/g
|
||||
}
|
||||
}
|
||||
},
|
||||
'pattern': /(\(|\s|\[|\=|:)(('|")([^\\\1]|\\.)*?(\3))/gm
|
||||
},
|
||||
{
|
||||
'name': 'comment',
|
||||
'pattern': /\/\*[\s\S]*?\*\/|(\/\/|\#)[\s\S]*?$/gm
|
||||
},
|
||||
{
|
||||
'name': 'constant.numeric',
|
||||
'pattern': /\b(\d+(\.\d+)?(e(\+|\-)?\d+)?(f|d)?|0x[\da-f]+)\b/gi
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'keyword'
|
||||
},
|
||||
'pattern': /\b(and|array|as|bool(ean)?|c(atch|har|lass|onst)|d(ef|elete|o(uble)?)|e(cho|lse(if)?|xit|xtends|xcept)|f(inally|loat|or(each)?|unction)|global|if|import|int(eger)?|long|new|object|or|pr(int|ivate|otected)|public|return|self|st(ring|ruct|atic)|switch|th(en|is|row)|try|(un)?signed|var|void|while)(?=\(|\b)/gi
|
||||
},
|
||||
{
|
||||
'name': 'constant.language',
|
||||
'pattern': /true|false|null/g
|
||||
},
|
||||
{
|
||||
'name': 'keyword.operator',
|
||||
'pattern': /\+|\!|\-|&(gt|lt|amp);|\||\*|\=/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'function.call'
|
||||
},
|
||||
'pattern': /(\w+?)(?=\()/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'storage.function',
|
||||
2: 'entity.name.function'
|
||||
},
|
||||
'pattern': /(function)\s(.*?)(?=\()/g
|
||||
}
|
||||
]);
|
||||
@@ -0,0 +1,83 @@
|
||||
/**
|
||||
* HTML patterns
|
||||
*
|
||||
* @author Craig Campbell
|
||||
* @version 1.0.7
|
||||
*/
|
||||
Rainbow.extend('html', [
|
||||
{
|
||||
'name': 'source.php.embedded',
|
||||
'matches': {
|
||||
2: {
|
||||
'language': 'php'
|
||||
}
|
||||
},
|
||||
'pattern': /<\?=?(?!xml)(php)?([\s\S]*?)(\?>)/gm
|
||||
},
|
||||
{
|
||||
'name': 'source.css.embedded',
|
||||
'matches': {
|
||||
0: {
|
||||
'language': 'css'
|
||||
}
|
||||
},
|
||||
'pattern': /<style(.*?)>([\s\S]*?)<\/style>/gm
|
||||
},
|
||||
{
|
||||
'name': 'source.js.embedded',
|
||||
'matches': {
|
||||
0: {
|
||||
'language': 'javascript'
|
||||
}
|
||||
},
|
||||
'pattern': /<script(?! src)(.*?)>([\s\S]*?)<\/script>/gm
|
||||
},
|
||||
{
|
||||
'name': 'comment.html',
|
||||
'pattern': /<\!--[\S\s]*?-->/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.tag.open',
|
||||
2: 'support.tag.close'
|
||||
},
|
||||
'pattern': /(<)|(\/?\??>)/g
|
||||
},
|
||||
{
|
||||
'name': 'support.tag',
|
||||
'matches': {
|
||||
1: 'support.tag',
|
||||
2: 'support.tag.special',
|
||||
3: 'support.tag-name'
|
||||
},
|
||||
'pattern': /(<\??)(\/|\!?)(\w+)/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.attribute'
|
||||
},
|
||||
'pattern': /([a-z-]+)(?=\=)/gi
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.operator',
|
||||
2: 'string.quote',
|
||||
3: 'string.value',
|
||||
4: 'string.quote'
|
||||
},
|
||||
'pattern': /(=)('|")(.*?)(\2)/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.operator',
|
||||
2: 'support.value'
|
||||
},
|
||||
'pattern': /(=)([a-zA-Z\-0-9]*)\b/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.attribute'
|
||||
},
|
||||
'pattern': /\s(\w+)(?=\s|>)(?![\s\S]*<)/g
|
||||
}
|
||||
], true);
|
||||
@@ -0,0 +1,110 @@
|
||||
/**
|
||||
* Javascript patterns
|
||||
*
|
||||
* @author Craig Campbell
|
||||
* @version 1.0.7
|
||||
*/
|
||||
Rainbow.extend('javascript', [
|
||||
|
||||
/**
|
||||
* matches $. or $(
|
||||
*/
|
||||
{
|
||||
'name': 'selector',
|
||||
'pattern': /(\s|^)\$(?=\.|\()/g
|
||||
},
|
||||
{
|
||||
'name': 'support',
|
||||
'pattern': /\b(window|document)\b/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.property'
|
||||
},
|
||||
'pattern': /\.(length|node(Name|Value))\b/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.function'
|
||||
},
|
||||
'pattern': /(setTimeout|setInterval)(?=\()/g
|
||||
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.method'
|
||||
},
|
||||
'pattern': /\.(getAttribute|push|getElementById|getElementsByClassName|log|setTimeout|setInterval)(?=\()/g
|
||||
},
|
||||
{
|
||||
'matches': {
|
||||
1: 'support.tag.script',
|
||||
2: [
|
||||
{
|
||||
'name': 'string',
|
||||
'pattern': /('|")(.*?)(\1)/g
|
||||
},
|
||||
{
|
||||
'name': 'entity.tag.script',
|
||||
'pattern': /(\w+)/g
|
||||
}
|
||||
],
|
||||
3: 'support.tag.script'
|
||||
},
|
||||
'pattern': /(<\/?)(script.*?)(>)/g
|
||||
},
|
||||
|
||||
/**
|
||||
* matches any escaped characters inside of a js regex pattern
|
||||
*
|
||||
* @see https://github.com/ccampbell/rainbow/issues/22
|
||||
*
|
||||
* this was causing single line comments to fail so it now makes sure
|
||||
* the opening / is not directly followed by a *
|
||||
*
|
||||
* @todo check that there is valid regex in match group 1
|
||||
*/
|
||||
{
|
||||
'name': 'string.regexp',
|
||||
'matches': {
|
||||
1: 'string.regexp.open',
|
||||
2: {
|
||||
'name': 'constant.regexp.escape',
|
||||
'pattern': /\\(.){1}/g
|
||||
},
|
||||
3: 'string.regexp.close',
|
||||
4: 'string.regexp.modifier'
|
||||
},
|
||||
'pattern': /(\/)(?!\*)(.+)(\/)([igm]{0,3})/g
|
||||
},
|
||||
|
||||
/**
|
||||
* matches runtime function declarations
|
||||
*/
|
||||
{
|
||||
'matches': {
|
||||
1: 'storage',
|
||||
3: 'entity.function'
|
||||
},
|
||||
'pattern': /(var)?(\s|^)(.*)(?=\s?=\s?function\()/g
|
||||
},
|
||||
|
||||
/**
|
||||
* matches constructor call
|
||||
*/
|
||||
{
|
||||
'matches': {
|
||||
1: 'keyword',
|
||||
2: 'entity.function'
|
||||
},
|
||||
'pattern': /(new)\s+(.*)(?=\()/g
|
||||
},
|
||||
|
||||
/**
|
||||
* matches any function call in the style functionName: function()
|
||||
*/
|
||||
{
|
||||
'name': 'entity.function',
|
||||
'pattern': /(\w+)(?=:\s{0,}function)/g
|
||||
}
|
||||
]);
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* GitHub theme
|
||||
*
|
||||
* @author Craig Campbell
|
||||
* @version 1.0.4
|
||||
*/
|
||||
pre {
|
||||
border: 1px solid #ccc;
|
||||
word-wrap: break-word;
|
||||
padding: 6px 10px;
|
||||
line-height: 19px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
code {
|
||||
border: 1px solid #eaeaea;
|
||||
margin: 0px 2px;
|
||||
padding: 0px 5px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
pre code {
|
||||
border: 0px;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
-moz-border-radius: 0px;
|
||||
-webkit-border-radius: 0px;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
pre, code {
|
||||
font-family: Consolas, 'Liberation Mono', Courier, monospace;
|
||||
color: #333;
|
||||
background: #f8f8f8;
|
||||
-moz-border-radius: 3px;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
pre, pre code {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
pre .comment {
|
||||
color: #998;
|
||||
}
|
||||
|
||||
pre .support {
|
||||
color: #0086B3;
|
||||
}
|
||||
|
||||
pre .tag, pre .tag-name {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
pre .keyword, pre .css-property, pre .vendor-prefix, pre .sass, pre .class, pre .id, pre .css-value, pre .entity.function, pre .storage.function {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
pre .css-property, pre .css-value, pre .vendor-prefix, pre .support.namespace {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
pre .constant.numeric, pre .keyword.unit, pre .hex-color {
|
||||
font-weight: normal;
|
||||
color: #099;
|
||||
}
|
||||
|
||||
pre .entity.class {
|
||||
color: #458;
|
||||
}
|
||||
|
||||
pre .entity.id, pre .entity.function {
|
||||
color: #900;
|
||||
}
|
||||
|
||||
pre .attribute, pre .variable {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
pre .string, pre .support.value {
|
||||
font-weight: normal;
|
||||
color: #d14;
|
||||
}
|
||||
|
||||
pre .regexp {
|
||||
color: #009926;
|
||||
}
|
||||
@@ -0,0 +1,773 @@
|
||||
/**
|
||||
* Copyright 2012 Craig Campbell
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Rainbow is a simple code syntax highlighter
|
||||
*
|
||||
* @preserve @version 1.1.8
|
||||
* @url rainbowco.de
|
||||
*/
|
||||
window['Rainbow'] = (function() {
|
||||
|
||||
/**
|
||||
* array of replacements to process at the end
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
var replacements = {},
|
||||
|
||||
/**
|
||||
* an array of start and end positions of blocks to be replaced
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
replacement_positions = {},
|
||||
|
||||
/**
|
||||
* an array of the language patterns specified for each language
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
language_patterns = {},
|
||||
|
||||
/**
|
||||
* an array of languages and whether they should bypass the default patterns
|
||||
*
|
||||
* @type {Object}
|
||||
*/
|
||||
bypass_defaults = {},
|
||||
|
||||
/**
|
||||
* processing level
|
||||
*
|
||||
* replacements are stored at this level so if there is a sub block of code
|
||||
* (for example php inside of html) it runs at a different level
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
CURRENT_LEVEL = 0,
|
||||
|
||||
/**
|
||||
* constant used to refer to the default language
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
DEFAULT_LANGUAGE = 0,
|
||||
|
||||
/**
|
||||
* used as counters so we can selectively call setTimeout
|
||||
* after processing a certain number of matches/replacements
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
match_counter = 0,
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
replacement_counter = 0,
|
||||
|
||||
/**
|
||||
* @type {null|string}
|
||||
*/
|
||||
global_class,
|
||||
|
||||
/**
|
||||
* @type {null|Function}
|
||||
*/
|
||||
onHighlight;
|
||||
|
||||
/**
|
||||
* cross browser get attribute for an element
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/3755227/cross-browser-javascript-getattribute-method
|
||||
*
|
||||
* @param {Node} el
|
||||
* @param {string} attr attribute you are trying to get
|
||||
* @returns {string|number}
|
||||
*/
|
||||
function _attr(el, attr, attrs, i) {
|
||||
var result = (el.getAttribute && el.getAttribute(attr)) || 0;
|
||||
|
||||
if (!result) {
|
||||
attrs = el.attributes;
|
||||
|
||||
for (i = 0; i < attrs.length; ++i) {
|
||||
if (attrs[i].nodeName === attr) {
|
||||
return attrs[i].nodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a class to a given code block
|
||||
*
|
||||
* @param {Element} el
|
||||
* @param {string} class_name class name to add
|
||||
* @returns void
|
||||
*/
|
||||
function _addClass(el, class_name) {
|
||||
el.className += el.className ? ' ' + class_name : class_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if a block has a given class
|
||||
*
|
||||
* @param {Element} el
|
||||
* @param {string} class_name class name to check for
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function _hasClass(el, class_name) {
|
||||
return (' ' + el.className + ' ').indexOf(' ' + class_name + ' ') > -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* gets the language for this block of code
|
||||
*
|
||||
* @param {Element} block
|
||||
* @returns {string|null}
|
||||
*/
|
||||
function _getLanguageForBlock(block) {
|
||||
|
||||
// if this doesn't have a language but the parent does then use that
|
||||
// this means if for example you have: <pre data-language="php">
|
||||
// with a bunch of <code> blocks inside then you do not have
|
||||
// to specify the language for each block
|
||||
var language = _attr(block, 'data-language') || _attr(block.parentNode, 'data-language');
|
||||
|
||||
// this adds support for specifying language via a css class
|
||||
// you can use the Google Code Prettify style: <pre class="lang-php">
|
||||
// or the HTML5 style: <pre><code class="language-php">
|
||||
if (!language) {
|
||||
var pattern = /\blang(?:uage)?-(\w+)/,
|
||||
match = block.className.match(pattern) || block.parentNode.className.match(pattern);
|
||||
|
||||
if (match) {
|
||||
language = match[1];
|
||||
}
|
||||
}
|
||||
|
||||
return language;
|
||||
}
|
||||
|
||||
/**
|
||||
* makes sure html entities are always used for tags
|
||||
*
|
||||
* @param {string} code
|
||||
* @returns {string}
|
||||
*/
|
||||
function _htmlEntities(code) {
|
||||
return code.replace(/</g, '<').replace(/>/g, '>').replace(/&(?![\w\#]+;)/g, '&');
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if a new match intersects with an existing one
|
||||
*
|
||||
* @param {number} start1 start position of existing match
|
||||
* @param {number} end1 end position of existing match
|
||||
* @param {number} start2 start position of new match
|
||||
* @param {number} end2 end position of new match
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function _intersects(start1, end1, start2, end2) {
|
||||
if (start2 >= start1 && start2 < end1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return end2 > start1 && end2 < end1;
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if two different matches have complete overlap with each other
|
||||
*
|
||||
* @param {number} start1 start position of existing match
|
||||
* @param {number} end1 end position of existing match
|
||||
* @param {number} start2 start position of new match
|
||||
* @param {number} end2 end position of new match
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function _hasCompleteOverlap(start1, end1, start2, end2) {
|
||||
|
||||
// if the starting and end positions are exactly the same
|
||||
// then the first one should stay and this one should be ignored
|
||||
if (start2 == start1 && end2 == end1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return start2 <= start1 && end2 >= end1;
|
||||
}
|
||||
|
||||
/**
|
||||
* determines if the match passed in falls inside of an existing match
|
||||
* this prevents a regex pattern from matching inside of a bigger pattern
|
||||
*
|
||||
* @param {number} start - start position of new match
|
||||
* @param {number} end - end position of new match
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function _matchIsInsideOtherMatch(start, end) {
|
||||
for (var key in replacement_positions[CURRENT_LEVEL]) {
|
||||
key = parseInt(key, 10);
|
||||
|
||||
// if this block completely overlaps with another block
|
||||
// then we should remove the other block and return false
|
||||
if (_hasCompleteOverlap(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
|
||||
delete replacement_positions[CURRENT_LEVEL][key];
|
||||
delete replacements[CURRENT_LEVEL][key];
|
||||
}
|
||||
|
||||
if (_intersects(key, replacement_positions[CURRENT_LEVEL][key], start, end)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* takes a string of code and wraps it in a span tag based on the name
|
||||
*
|
||||
* @param {string} name name of the pattern (ie keyword.regex)
|
||||
* @param {string} code block of code to wrap
|
||||
* @returns {string}
|
||||
*/
|
||||
function _wrapCodeInSpan(name, code) {
|
||||
return '<span class="' + name.replace(/\./g, ' ') + (global_class ? ' ' + global_class : '') + '">' + code + '</span>';
|
||||
}
|
||||
|
||||
/**
|
||||
* finds out the position of group match for a regular expression
|
||||
*
|
||||
* @see http://stackoverflow.com/questions/1985594/how-to-find-index-of-groups-in-match
|
||||
*
|
||||
* @param {Object} match
|
||||
* @param {number} group_number
|
||||
* @returns {number}
|
||||
*/
|
||||
function _indexOfGroup(match, group_number) {
|
||||
var index = 0,
|
||||
i;
|
||||
|
||||
for (i = 1; i < group_number; ++i) {
|
||||
if (match[i]) {
|
||||
index += match[i].length;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* matches a regex pattern against a block of code
|
||||
* finds all matches that should be processed and stores the positions
|
||||
* of where they should be replaced within the string
|
||||
*
|
||||
* this is where pretty much all the work is done but it should not
|
||||
* be called directly
|
||||
*
|
||||
* @param {RegExp} pattern
|
||||
* @param {string} code
|
||||
* @returns void
|
||||
*/
|
||||
function _processPattern(regex, pattern, code, callback)
|
||||
{
|
||||
var match = regex.exec(code);
|
||||
|
||||
if (!match) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
++match_counter;
|
||||
|
||||
// treat match 0 the same way as name
|
||||
if (!pattern['name'] && typeof pattern['matches'][0] == 'string') {
|
||||
pattern['name'] = pattern['matches'][0];
|
||||
delete pattern['matches'][0];
|
||||
}
|
||||
|
||||
var replacement = match[0],
|
||||
start_pos = match.index,
|
||||
end_pos = match[0].length + start_pos,
|
||||
|
||||
/**
|
||||
* callback to process the next match of this pattern
|
||||
*/
|
||||
processNext = function() {
|
||||
var nextCall = function() {
|
||||
_processPattern(regex, pattern, code, callback);
|
||||
};
|
||||
|
||||
// every 100 items we process let's call set timeout
|
||||
// to let the ui breathe a little
|
||||
return match_counter % 100 > 0 ? nextCall() : setTimeout(nextCall, 0);
|
||||
};
|
||||
|
||||
// if this is not a child match and it falls inside of another
|
||||
// match that already happened we should skip it and continue processing
|
||||
if (_matchIsInsideOtherMatch(start_pos, end_pos)) {
|
||||
return processNext();
|
||||
}
|
||||
|
||||
/**
|
||||
* callback for when a match was successfully processed
|
||||
*
|
||||
* @param {string} replacement
|
||||
* @returns void
|
||||
*/
|
||||
var onMatchSuccess = function(replacement) {
|
||||
// if this match has a name then wrap it in a span tag
|
||||
if (pattern['name']) {
|
||||
replacement = _wrapCodeInSpan(pattern['name'], replacement);
|
||||
}
|
||||
|
||||
// console.log('LEVEL', CURRENT_LEVEL, 'replace', match[0], 'with', replacement, 'at position', start_pos, 'to', end_pos);
|
||||
|
||||
// store what needs to be replaced with what at this position
|
||||
if (!replacements[CURRENT_LEVEL]) {
|
||||
replacements[CURRENT_LEVEL] = {};
|
||||
replacement_positions[CURRENT_LEVEL] = {};
|
||||
}
|
||||
|
||||
replacements[CURRENT_LEVEL][start_pos] = {
|
||||
'replace': match[0],
|
||||
'with': replacement
|
||||
};
|
||||
|
||||
// store the range of this match so we can use it for comparisons
|
||||
// with other matches later
|
||||
replacement_positions[CURRENT_LEVEL][start_pos] = end_pos;
|
||||
|
||||
// process the next match
|
||||
processNext();
|
||||
},
|
||||
|
||||
// if this pattern has sub matches for different groups in the regex
|
||||
// then we should process them one at a time by rerunning them through
|
||||
// this function to generate the new replacement
|
||||
//
|
||||
// we run through them backwards because the match position of earlier
|
||||
// matches will not change depending on what gets replaced in later
|
||||
// matches
|
||||
group_keys = keys(pattern['matches']),
|
||||
|
||||
/**
|
||||
* callback for processing a sub group
|
||||
*
|
||||
* @param {number} i
|
||||
* @param {Array} group_keys
|
||||
* @param {Function} callback
|
||||
*/
|
||||
processGroup = function(i, group_keys, callback) {
|
||||
if (i >= group_keys.length) {
|
||||
return callback(replacement);
|
||||
}
|
||||
|
||||
var processNextGroup = function() {
|
||||
processGroup(++i, group_keys, callback);
|
||||
},
|
||||
block = match[group_keys[i]];
|
||||
|
||||
// if there is no match here then move on
|
||||
if (!block) {
|
||||
return processNextGroup();
|
||||
}
|
||||
|
||||
var group = pattern['matches'][group_keys[i]],
|
||||
language = group['language'],
|
||||
|
||||
/**
|
||||
* process group is what group we should use to actually process
|
||||
* this match group
|
||||
*
|
||||
* for example if the subgroup pattern looks like this
|
||||
* 2: {
|
||||
* 'name': 'keyword',
|
||||
* 'pattern': /true/g
|
||||
* }
|
||||
*
|
||||
* then we use that as is, but if it looks like this
|
||||
*
|
||||
* 2: {
|
||||
* 'name': 'keyword',
|
||||
* 'matches': {
|
||||
* 'name': 'special',
|
||||
* 'pattern': /whatever/g
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* we treat the 'matches' part as the pattern and keep
|
||||
* the name around to wrap it with later
|
||||
*/
|
||||
process_group = group['name'] && group['matches'] ? group['matches'] : group,
|
||||
|
||||
/**
|
||||
* takes the code block matched at this group, replaces it
|
||||
* with the highlighted block, and optionally wraps it with
|
||||
* a span with a name
|
||||
*
|
||||
* @param {string} block
|
||||
* @param {string} replace_block
|
||||
* @param {string|null} match_name
|
||||
*/
|
||||
_replaceAndContinue = function(block, replace_block, match_name) {
|
||||
replacement = _replaceAtPosition(_indexOfGroup(match, group_keys[i]), block, match_name ? _wrapCodeInSpan(match_name, replace_block) : replace_block, replacement);
|
||||
processNextGroup();
|
||||
};
|
||||
|
||||
// if this is a sublanguage go and process the block using that language
|
||||
if (language) {
|
||||
return _highlightBlockForLanguage(block, language, function(code) {
|
||||
_replaceAndContinue(block, code);
|
||||
});
|
||||
}
|
||||
|
||||
// if this is a string then this match is directly mapped to selector
|
||||
// so all we have to do is wrap it in a span and continue
|
||||
if (typeof group === 'string') {
|
||||
return _replaceAndContinue(block, block, group);
|
||||
}
|
||||
|
||||
// the process group can be a single pattern or an array of patterns
|
||||
// _processCodeWithPatterns always expects an array so we convert it here
|
||||
_processCodeWithPatterns(block, process_group.length ? process_group : [process_group], function(code) {
|
||||
_replaceAndContinue(block, code, group['matches'] ? group['name'] : 0);
|
||||
});
|
||||
};
|
||||
|
||||
processGroup(0, group_keys, onMatchSuccess);
|
||||
}
|
||||
|
||||
/**
|
||||
* should a language bypass the default patterns?
|
||||
*
|
||||
* if you call Rainbow.extend() and pass true as the third argument
|
||||
* it will bypass the defaults
|
||||
*/
|
||||
function _bypassDefaultPatterns(language)
|
||||
{
|
||||
return bypass_defaults[language];
|
||||
}
|
||||
|
||||
/**
|
||||
* returns a list of regex patterns for this language
|
||||
*
|
||||
* @param {string} language
|
||||
* @returns {Array}
|
||||
*/
|
||||
function _getPatternsForLanguage(language) {
|
||||
var patterns = language_patterns[language] || [],
|
||||
default_patterns = language_patterns[DEFAULT_LANGUAGE] || [];
|
||||
|
||||
return _bypassDefaultPatterns(language) ? patterns : patterns.concat(default_patterns);
|
||||
}
|
||||
|
||||
/**
|
||||
* substring replace call to replace part of a string at a certain position
|
||||
*
|
||||
* @param {number} position the position where the replacement should happen
|
||||
* @param {string} replace the text we want to replace
|
||||
* @param {string} replace_with the text we want to replace it with
|
||||
* @param {string} code the code we are doing the replacing in
|
||||
* @returns {string}
|
||||
*/
|
||||
function _replaceAtPosition(position, replace, replace_with, code) {
|
||||
var sub_string = code.substr(position);
|
||||
return code.substr(0, position) + sub_string.replace(replace, replace_with);
|
||||
}
|
||||
|
||||
/**
|
||||
* sorts an object by index descending
|
||||
*
|
||||
* @param {Object} object
|
||||
* @return {Array}
|
||||
*/
|
||||
function keys(object) {
|
||||
var locations = [],
|
||||
replacement,
|
||||
pos;
|
||||
|
||||
for(var location in object) {
|
||||
if (object.hasOwnProperty(location)) {
|
||||
locations.push(location);
|
||||
}
|
||||
}
|
||||
|
||||
// numeric descending
|
||||
return locations.sort(function(a, b) {
|
||||
return b - a;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* processes a block of code using specified patterns
|
||||
*
|
||||
* @param {string} code
|
||||
* @param {Array} patterns
|
||||
* @returns void
|
||||
*/
|
||||
function _processCodeWithPatterns(code, patterns, callback)
|
||||
{
|
||||
// we have to increase the level here so that the
|
||||
// replacements will not conflict with each other when
|
||||
// processing sub blocks of code
|
||||
++CURRENT_LEVEL;
|
||||
|
||||
// patterns are processed one at a time through this function
|
||||
function _workOnPatterns(patterns, i)
|
||||
{
|
||||
// still have patterns to process, keep going
|
||||
if (i < patterns.length) {
|
||||
return _processPattern(patterns[i]['pattern'], patterns[i], code, function() {
|
||||
_workOnPatterns(patterns, ++i);
|
||||
});
|
||||
}
|
||||
|
||||
// we are done processing the patterns
|
||||
// process the replacements and update the DOM
|
||||
_processReplacements(code, function(code) {
|
||||
|
||||
// when we are done processing replacements
|
||||
// we are done at this level so we can go back down
|
||||
delete replacements[CURRENT_LEVEL];
|
||||
delete replacement_positions[CURRENT_LEVEL];
|
||||
--CURRENT_LEVEL;
|
||||
callback(code);
|
||||
});
|
||||
}
|
||||
|
||||
_workOnPatterns(patterns, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* process replacements in the string of code to actually update the markup
|
||||
*
|
||||
* @param {string} code the code to process replacements in
|
||||
* @param {Function} onComplete what to do when we are done processing
|
||||
* @returns void
|
||||
*/
|
||||
function _processReplacements(code, onComplete) {
|
||||
|
||||
/**
|
||||
* processes a single replacement
|
||||
*
|
||||
* @param {string} code
|
||||
* @param {Array} positions
|
||||
* @param {number} i
|
||||
* @param {Function} onComplete
|
||||
* @returns void
|
||||
*/
|
||||
function _processReplacement(code, positions, i, onComplete) {
|
||||
if (i < positions.length) {
|
||||
++replacement_counter;
|
||||
var pos = positions[i],
|
||||
replacement = replacements[CURRENT_LEVEL][pos];
|
||||
code = _replaceAtPosition(pos, replacement['replace'], replacement['with'], code);
|
||||
|
||||
// process next function
|
||||
var next = function() {
|
||||
_processReplacement(code, positions, ++i, onComplete);
|
||||
};
|
||||
|
||||
// use a timeout every 250 to not freeze up the UI
|
||||
return replacement_counter % 250 > 0 ? next() : setTimeout(next, 0);
|
||||
}
|
||||
|
||||
onComplete(code);
|
||||
}
|
||||
|
||||
var string_positions = keys(replacements[CURRENT_LEVEL]);
|
||||
_processReplacement(code, string_positions, 0, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* takes a string of code and highlights it according to the language specified
|
||||
*
|
||||
* @param {string} code
|
||||
* @param {string} language
|
||||
* @param {Function} onComplete
|
||||
* @returns void
|
||||
*/
|
||||
function _highlightBlockForLanguage(code, language, onComplete) {
|
||||
var patterns = _getPatternsForLanguage(language);
|
||||
_processCodeWithPatterns(_htmlEntities(code), patterns, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* highlight an individual code block
|
||||
*
|
||||
* @param {Array} code_blocks
|
||||
* @param {number} i
|
||||
* @returns void
|
||||
*/
|
||||
function _highlightCodeBlock(code_blocks, i, onComplete) {
|
||||
if (i < code_blocks.length) {
|
||||
var block = code_blocks[i],
|
||||
language = _getLanguageForBlock(block);
|
||||
|
||||
if (!_hasClass(block, 'rainbow') && language) {
|
||||
language = language.toLowerCase();
|
||||
|
||||
_addClass(block, 'rainbow');
|
||||
|
||||
return _highlightBlockForLanguage(block.innerHTML, language, function(code) {
|
||||
block.innerHTML = code;
|
||||
|
||||
// reset the replacement arrays
|
||||
replacements = {};
|
||||
replacement_positions = {};
|
||||
|
||||
// if you have a listener attached tell it that this block is now highlighted
|
||||
if (onHighlight) {
|
||||
onHighlight(block, language);
|
||||
}
|
||||
|
||||
// process the next block
|
||||
setTimeout(function() {
|
||||
_highlightCodeBlock(code_blocks, ++i, onComplete);
|
||||
}, 0);
|
||||
});
|
||||
}
|
||||
return _highlightCodeBlock(code_blocks, ++i, onComplete);
|
||||
}
|
||||
|
||||
if (onComplete) {
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* start highlighting all the code blocks
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
function _highlight(node, onComplete) {
|
||||
|
||||
// the first argument can be an Event or a DOM Element
|
||||
// I was originally checking instanceof Event but that makes it break
|
||||
// when using mootools
|
||||
//
|
||||
// @see https://github.com/ccampbell/rainbow/issues/32
|
||||
//
|
||||
node = node && typeof node.getElementsByTagName == 'function' ? node : document;
|
||||
|
||||
var pre_blocks = node.getElementsByTagName('pre'),
|
||||
code_blocks = node.getElementsByTagName('code'),
|
||||
i,
|
||||
final_blocks = [];
|
||||
|
||||
// @see http://stackoverflow.com/questions/2735067/how-to-convert-a-dom-node-list-to-an-array-in-javascript
|
||||
// we are going to process all <code> blocks
|
||||
for (i = 0; i < code_blocks.length; ++i) {
|
||||
final_blocks.push(code_blocks[i]);
|
||||
}
|
||||
|
||||
// loop through the pre blocks to see which ones we should add
|
||||
for (i = 0; i < pre_blocks.length; ++i) {
|
||||
|
||||
// if the pre block has no code blocks then process it directly
|
||||
if (!pre_blocks[i].getElementsByTagName('code').length) {
|
||||
final_blocks.push(pre_blocks[i]);
|
||||
}
|
||||
}
|
||||
|
||||
_highlightCodeBlock(final_blocks, 0, onComplete);
|
||||
}
|
||||
|
||||
/**
|
||||
* public methods
|
||||
*/
|
||||
return {
|
||||
|
||||
/**
|
||||
* extends the language pattern matches
|
||||
*
|
||||
* @param {*} language name of language
|
||||
* @param {*} patterns array of patterns to add on
|
||||
* @param {boolean|null} bypass if true this will bypass the default language patterns
|
||||
*/
|
||||
extend: function(language, patterns, bypass) {
|
||||
|
||||
// if there is only one argument then we assume that we want to
|
||||
// extend the default language rules
|
||||
if (arguments.length == 1) {
|
||||
patterns = language;
|
||||
language = DEFAULT_LANGUAGE;
|
||||
}
|
||||
|
||||
bypass_defaults[language] = bypass;
|
||||
language_patterns[language] = patterns.concat(language_patterns[language] || []);
|
||||
},
|
||||
|
||||
/**
|
||||
* call back to let you do stuff in your app after a piece of code has been highlighted
|
||||
*
|
||||
* @param {Function} callback
|
||||
*/
|
||||
onHighlight: function(callback) {
|
||||
onHighlight = callback;
|
||||
},
|
||||
|
||||
/**
|
||||
* method to set a global class that will be applied to all spans
|
||||
*
|
||||
* @param {string} class_name
|
||||
*/
|
||||
addClass: function(class_name) {
|
||||
global_class = class_name;
|
||||
},
|
||||
|
||||
/**
|
||||
* starts the magic rainbow
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
color: function() {
|
||||
|
||||
// if you want to straight up highlight a string you can pass the string of code,
|
||||
// the language, and a callback function
|
||||
if (typeof arguments[0] == 'string') {
|
||||
return _highlightBlockForLanguage(arguments[0], arguments[1], arguments[2]);
|
||||
}
|
||||
|
||||
// if you pass a callback function then we rerun the color function
|
||||
// on all the code and call the callback function on complete
|
||||
if (typeof arguments[0] == 'function') {
|
||||
return _highlight(0, arguments[0]);
|
||||
}
|
||||
|
||||
// otherwise we use whatever node you passed in with an optional
|
||||
// callback function as the second parameter
|
||||
_highlight(arguments[0], arguments[1]);
|
||||
}
|
||||
};
|
||||
}) ();
|
||||
|
||||
/**
|
||||
* adds event listener to start highlighting
|
||||
*/
|
||||
(function() {
|
||||
if (window.addEventListener) {
|
||||
return window.addEventListener('load', Rainbow.color, false);
|
||||
}
|
||||
window.attachEvent('onload', Rainbow.color);
|
||||
}) ();
|
||||
|
||||
// When using Google closure compiler in advanced mode some methods
|
||||
// get renamed. This keeps a public reference to these methods so they can
|
||||
// still be referenced from outside this library.
|
||||
Rainbow["onHighlight"] = Rainbow.onHighlight;
|
||||
Rainbow["addClass"] = Rainbow.addClass;
|
||||
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" ng-app="bootstrapDemoApp" id="top">
|
||||
<head>
|
||||
<title>Bootstrap for AngularUI</title>
|
||||
|
||||
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.2/angular.min.js"></script>
|
||||
<script src="ui-bootstrap.js"></script>
|
||||
<script>
|
||||
angular.module('bootstrapDemoApp', ['ui.bootstrap', <%= templateModules %>]);
|
||||
</script>
|
||||
<script>
|
||||
<%= templates %>
|
||||
</script>
|
||||
<link rel="stylesheet" href="assets/bootstrap.css" />
|
||||
<link rel="stylesheet" href="assets/rainbow.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" href="demo.html">ui-bootstrap</a>
|
||||
<div class="nav-collapse">
|
||||
<ul class="nav">
|
||||
<% modules.forEach(function(module) { %>
|
||||
<li><a href="#<%= module.name %>"><%= module.name %></a></li>
|
||||
<% }); %>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
<div style="margin: 32px;"></div>
|
||||
<div role="main">
|
||||
<div class="container">
|
||||
<% modules.forEach(function(module) { %>
|
||||
<section id="<%= module.name %>">
|
||||
<div class="page-header">
|
||||
<h1><%= module.name %></h1>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<%= module.html %>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<%= module.description %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<pre ng-non-bindable><code data-language="html"><%- module.html %></code></pre>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<pre ng-non-bindable><code data-language="javascript"><%- module.js %></code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<script><%= module.js %></script>
|
||||
<% }); %>
|
||||
</div>
|
||||
</div>
|
||||
<script src="assets/rainbow.js"></script>
|
||||
<script src="assets/rainbow-generic.js"></script>
|
||||
<script src="assets/rainbow-javascript.js"></script>
|
||||
<script src="assets/rainbow-html.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
+2
-2
@@ -2,9 +2,9 @@
|
||||
"author": "https://github.com/angular-ui/bootstrap/graphs/contributors",
|
||||
"name": "angular-ui-bootstrap",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"node-markdown": "*",
|
||||
"grunt": "~0.3.17"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Accordion is an angular-version of bootstrap's accordion.
|
||||
|
||||
**This** has *markdown* in it.
|
||||
@@ -0,0 +1,10 @@
|
||||
<li class="dropdown" ng-controller="DropdownCtrl">
|
||||
<a class="dropdown-toggle">
|
||||
Click me for a dropdown, yo!
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="choice in items">
|
||||
<a>{{choice}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -0,0 +1,7 @@
|
||||
function DropdownCtrl($scope) {
|
||||
$scope.items = [
|
||||
"The first choice!",
|
||||
"And another choice for you.",
|
||||
"but wait! A third!"
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
|
||||
DropdownToggle is a simple directive which will toggle a dropdown link on click. Simply put it on the `<a>` tag of the toggler-element, and it will find the nearest dropdown menu and toggle it when the `<a dropdown-toggle>` is clicked.
|
||||
+6
-5
@@ -6,10 +6,10 @@ basePath = '.';
|
||||
files = [
|
||||
JASMINE,
|
||||
JASMINE_ADAPTER,
|
||||
'test/lib/jquery-1.8.2.min.js',
|
||||
'test/lib/angular-1.0.2.js',
|
||||
'test/lib/angular-1.0.2-mocks.js',
|
||||
'test/lib/helpers.js',
|
||||
'misc/test-lib/jquery-1.8.2.min.js',
|
||||
'misc/test-lib/angular-1.0.2.js',
|
||||
'misc/test-lib/angular-1.0.2-mocks.js',
|
||||
'misc/test-lib/helpers.js',
|
||||
'src/**/*.js',
|
||||
'template/**/*.js'
|
||||
];
|
||||
@@ -25,7 +25,7 @@ exclude = [
|
||||
// - Opera
|
||||
// - Safari
|
||||
// - PhantomJS
|
||||
browsers = ['Chrome'];
|
||||
browsers = [];
|
||||
|
||||
// test results reporter to use
|
||||
// possible values: dots || progress
|
||||
@@ -50,3 +50,4 @@ autoWatch = true;
|
||||
// Continuous Integration mode
|
||||
// if true, it capture browsers, run tests and exit
|
||||
singleRun = false;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user