├── .gitattributes ├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── Makefile ├── bower.json ├── dist ├── angular-blocks.js └── angular-blocks.min.js ├── karma.conf.js ├── npm-shrinkwrap.json ├── package.json ├── readme.md ├── src ├── .jshintrc └── angular-blocks.js └── test ├── .jshintrc └── angular-blocks-spec.js /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set default behaviour, in case users don't have core.autocrlf set. 2 | * text=auto 3 | 4 | # Explicitly declare text files we want to always be normalized and converted 5 | # to native line endings on checkout. 6 | *.js text 7 | *.html text -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | coverage 3 | node_modules 4 | reports 5 | bower_components 6 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "browser": false, 4 | "jquery": false, 5 | "bitwise": true, 6 | "camelcase": false, 7 | "latedef": true, 8 | "boss": false, 9 | "curly": true, 10 | "debug": false, 11 | "devel": false, 12 | "eqeqeq": true, 13 | "evil": true, 14 | "forin": true, 15 | "immed": true, 16 | "laxbreak": false, 17 | "newcap": true, 18 | "noarg": true, 19 | "noempty": true, 20 | "nonew": true, 21 | "nomen": false, 22 | "onevar": false, 23 | "plusplus": true, 24 | "regexp": false, 25 | "undef": true, 26 | "sub": true, 27 | "strict": true, 28 | "white": false, 29 | "unused": true, 30 | "smarttabs": false, 31 | "indent": 4, 32 | "quotmark": "single" 33 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | before_script: 5 | - npm install grunt-cli -g 6 | - npm install bower -g 7 | - bower install 8 | after_script: 9 | - npm run coveralls 10 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 'use strict'; 3 | 4 | // Project configuration. 5 | grunt.initConfig({ 6 | pkg: grunt.file.readJSON('package.json'), 7 | lifecycle: { 8 | validate: [ 9 | 'jshint' 10 | ], 11 | compile: [], 12 | test: [ 13 | 'karma:phantom' 14 | ], 15 | 'package': [ 16 | 'concat', 17 | 'uglify' 18 | ], 19 | 'integration-test': [], 20 | verify: [], 21 | install: [], 22 | deploy: [] 23 | }, 24 | jshint: { 25 | src: { 26 | options: { 27 | jshintrc: 'src/.jshintrc' 28 | }, 29 | src: ['src/**/*.js'] 30 | }, 31 | test: { 32 | options: { 33 | jshintrc: 'test/.jshintrc' 34 | }, 35 | src: ['test/**/*.js'] 36 | }, 37 | grunt: { 38 | options: { 39 | jshintrc: '.jshintrc' 40 | }, 41 | src: ['Gruntfile.js'] 42 | } 43 | }, 44 | karma: { 45 | options: { 46 | configFile: 'karma.conf.js' 47 | }, 48 | unit: { 49 | singleRun: true 50 | }, 51 | phantom: { 52 | singleRun: true, 53 | browsers: ['PhantomJS'] 54 | }, 55 | chrome: { 56 | singleRun: true, 57 | browsers: ['Chrome'] 58 | }, 59 | debug: { 60 | singleRun: false 61 | } 62 | }, 63 | 64 | concat: { 65 | options: { 66 | banner: ['/**! ', 67 | ' * <%= pkg.name %> v<%= pkg.version %>', 68 | ' * Copyright (c) 2013 <%= pkg.author.name %>. <%= pkg.homepage %>', 69 | ' * License: MIT', 70 | ' */\n'].join('\n') 71 | }, 72 | scripts: { 73 | src: [ 74 | 'src/*.js' 75 | ], 76 | dest: 'dist/<%= pkg.name %>.js' 77 | } 78 | }, 79 | 80 | uglify: { 81 | options: { 82 | banner: ['/**! ', 83 | ' * <%= pkg.name %> v<%= pkg.version %>', 84 | ' * Copyright (c) 2013 <%= pkg.author.name %>. <%= pkg.homepage %>', 85 | ' * License: MIT', 86 | ' */\n'].join('\n') 87 | }, 88 | dist: { 89 | files: { 90 | 'dist/<%= pkg.name %>.min.js': ['<%= concat.scripts.dest %>'] 91 | } 92 | } 93 | }, 94 | regarde: { 95 | scripts: { 96 | files: ['src/**/*.js'], 97 | tasks: ['concat', 'uglify'] 98 | } 99 | }, 100 | bumpup: ['package.json', 'bower.json'], 101 | exec: { 102 | release_start: { 103 | command: 'git flow release start <%= pkg.version %>' 104 | }, 105 | release_finish: { 106 | command: 'git flow release finish <%= pkg.version %>' 107 | } 108 | } 109 | }); 110 | 111 | // load all grunt tasks 112 | require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks); 113 | 114 | grunt.registerTask('bump', function (type) { 115 | type = type ? type : 'patch'; 116 | grunt.task.run('bumpup:' + type); 117 | }); 118 | 119 | grunt.registerTask('test-phantom', ['karma:phantom']); 120 | grunt.registerTask('test-start', ['karma:debug:start']); 121 | grunt.registerTask('test-run', ['karma:debug:run']); 122 | grunt.registerTask('build', ['install']); 123 | grunt.registerTask('default', ['install']); 124 | 125 | }; 126 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 William L. Bunselmeyer. https://github.com/wmluke/angular-blocks 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VERSION=$(grep 'version' package.json | sed 's/.*\"\(.*\)\".*/\1/') 2 | 3 | install: 4 | npm install # Install node modules 5 | bower install # Install bower components 6 | grunt install # Build & test client app 7 | 8 | release: 9 | grunt bump 10 | make install 11 | git add dist bower.json package.json 12 | git commit -m "Bumped version to $(value VERSION)" 13 | git tag -a $(value VERSION) -m "v$(value VERSION)" 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-blocks", 3 | "description": "Template inheritance for Angular JS", 4 | "version": "0.1.10", 5 | "main": [ 6 | "dist/angular-blocks.js" 7 | ], 8 | "ignore": [ 9 | "components", 10 | "test", 11 | ".jshintrc", 12 | "karma.conf.js", 13 | "Gruntfile.js" 14 | ], 15 | "dependencies": { 16 | "jquery": ">1.9", 17 | "angular": "1.x" 18 | }, 19 | "devDependencies": { 20 | "jquery": "=1.11.1", 21 | "angular": "=1.4.9", 22 | "angular-mocks": "=1.4.9", 23 | "angular-scenario": "=1.4.9" 24 | } 25 | } -------------------------------------------------------------------------------- /dist/angular-blocks.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * angular-blocks v0.1.10 3 | * Copyright (c) 2013 William L. Bunselmeyer. https://github.com/wmluke/angular-blocks 4 | * License: MIT 5 | */ 6 | /* global angular */ 7 | (function () { 8 | 'use strict'; 9 | 10 | function extendTemplate($templateCache, $compile, $http, $q, $log, $timeout) { 11 | 12 | function warnMissingBlock(name, src) { 13 | $log.warn('Failed to find data-block=' + name + ' in ' + src); 14 | } 15 | 16 | return { 17 | compile: function (tElement, tAttrs) { 18 | var src = tAttrs.extendTemplate; 19 | if (!src) { 20 | throw 'Template not specified in extend-template directive'; 21 | } 22 | 23 | // Clone and then clear the template element to prevent expressions from being evaluated 24 | var $clone = tElement.clone(); 25 | tElement.html(''); 26 | 27 | var loadTemplate = $http.get(src, {cache: $templateCache}) 28 | .then(function (response) { 29 | var template = response.data; 30 | var $template = $(document.createElement('div')).html(template); 31 | 32 | function override(method, $block, attr) { 33 | var name = $block.attr(attr); 34 | if ($template.find('[data-block="' + name + '"]')[method]($block).length === 0 && 35 | $template.find('[data-extend-template]').append($block).length === 0) { 36 | warnMissingBlock(name, src); 37 | } 38 | } 39 | 40 | // Replace overridden blocks 41 | $clone.children('[data-block]').each(function () { 42 | override('replaceWith', $(this), 'data-block'); 43 | }); 44 | 45 | // Insert prepend blocks 46 | $clone.children('[data-block-prepend]').each(function () { 47 | override('prepend', $(this), 'data-block-prepend'); 48 | }); 49 | 50 | // Insert append blocks 51 | $clone.children('[data-block-append]').each(function () { 52 | override('append', $(this), 'data-block-append'); 53 | }); 54 | 55 | // Insert before blocks 56 | $clone.children('[data-block-before]').each(function () { 57 | override('before', $(this), 'data-block-before'); 58 | }); 59 | 60 | // Insert after blocks 61 | $clone.children('[data-block-after]').each(function () { 62 | override('after', $(this), 'data-block-after'); 63 | }); 64 | 65 | return $template; 66 | }, function () { 67 | var msg = 'Failed to load template: ' + src; 68 | $log.error(msg); 69 | return $q.reject(msg); 70 | }); 71 | 72 | 73 | return function ($scope, $element) { 74 | loadTemplate.then(function ($template) { 75 | $scope.$broadcast('$blocksExtendTemplateLinkStart', src); 76 | $element.html($template.html()); 77 | $compile($element.contents())($scope); 78 | $timeout(function () { 79 | $scope.$broadcast('$blocksExtendTemplateLinkFinish', src); 80 | }); 81 | }); 82 | }; 83 | } 84 | }; 85 | } 86 | 87 | angular.module('angular-blocks', []) 88 | .directive('extendTemplate', ['$templateCache', '$compile', '$http', '$q', '$log', '$timeout', extendTemplate]); 89 | }()); 90 | -------------------------------------------------------------------------------- /dist/angular-blocks.min.js: -------------------------------------------------------------------------------- 1 | /**! 2 | * angular-blocks v0.1.10 3 | * Copyright (c) 2013 William L. Bunselmeyer. https://github.com/wmluke/angular-blocks 4 | * License: MIT 5 | */ 6 | !function(){"use strict";function a(a,b,c,d,e,f){function g(a,b){e.warn("Failed to find data-block="+a+" in "+b)}return{compile:function(h,i){var j=i.extendTemplate;if(!j)throw"Template not specified in extend-template directive";var k=h.clone();h.html("");var l=c.get(j,{cache:a}).then(function(a){function b(a,b,c){var e=b.attr(c);0===d.find('[data-block="'+e+'"]')[a](b).length&&0===d.find("[data-extend-template]").append(b).length&&g(e,j)}var c=a.data,d=$(document.createElement("div")).html(c);return k.children("[data-block]").each(function(){b("replaceWith",$(this),"data-block")}),k.children("[data-block-prepend]").each(function(){b("prepend",$(this),"data-block-prepend")}),k.children("[data-block-append]").each(function(){b("append",$(this),"data-block-append")}),k.children("[data-block-before]").each(function(){b("before",$(this),"data-block-before")}),k.children("[data-block-after]").each(function(){b("after",$(this),"data-block-after")}),d},function(){var a="Failed to load template: "+j;return e.error(a),d.reject(a)});return function(a,c){l.then(function(d){a.$broadcast("$blocksExtendTemplateLinkStart",j),c.html(d.html()),b(c.contents())(a),f(function(){a.$broadcast("$blocksExtendTemplateLinkFinish",j)})})}}}}angular.module("angular-blocks",[]).directive("extendTemplate",["$templateCache","$compile","$http","$q","$log","$timeout",a])}(); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Fri Aug 09 2013 09:44:05 GMT-0700 (PDT) 3 | 4 | module.exports = function (config) { 5 | 'use strict'; 6 | 7 | config.set({ 8 | 9 | // base path, that will be used to resolve files and exclude 10 | basePath: '', 11 | 12 | // frameworks to use 13 | frameworks: ['jasmine'], 14 | 15 | // list of files / patterns to load in the browser 16 | files: [ 17 | 'bower_components/jquery/dist/jquery.js', 18 | 'bower_components/angular/angular.js', 19 | 'bower_components/angular-mocks/angular-mocks.js', 20 | 'src/*.js', 21 | 'test/*-spec.js' 22 | ], 23 | 24 | // list of files to exclude 25 | exclude: [], 26 | 27 | // test results reporter to use 28 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 29 | reporters: ['progress', 'junit', 'coverage'], 30 | 31 | preprocessors: { 32 | // source files, that you wanna generate coverage for 33 | // do not include tests or libraries 34 | // (these files will be instrumented by Istanbul) 35 | 'src/*.js': ['coverage'] 36 | }, 37 | 38 | coverageReporter: { 39 | type: 'lcov', // lcov format supported by Coveralls 40 | dir: 'reports/coverage' 41 | }, 42 | 43 | junitReporter: { 44 | outputFile: 'reports/test/unit-test-results.xml' 45 | }, 46 | 47 | // web server port 48 | port: 9876, 49 | 50 | runnerPort: 9100, 51 | 52 | // enable / disable colors in the output (reporters and logs) 53 | colors: true, 54 | 55 | // level of logging 56 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 57 | logLevel: config.LOG_INFO, 58 | 59 | // enable / disable watching file and executing tests whenever any file changes 60 | autoWatch: false, 61 | 62 | // Start these browsers, currently available: 63 | // - Chrome 64 | // - ChromeCanary 65 | // - Firefox 66 | // - Opera 67 | // - Safari (only Mac) 68 | // - PhantomJS 69 | // - IE (only Windows) 70 | browsers: ['PhantomJS'], 71 | 72 | // If browser does not capture in given timeout [ms], kill it 73 | captureTimeout: 5000, 74 | 75 | // Continuous Integration mode 76 | // if true, it capture browsers, run tests and exit 77 | singleRun: false 78 | }); 79 | }; 80 | 81 | -------------------------------------------------------------------------------- /npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-blocks", 3 | "version": "0.1.9", 4 | "dependencies": { 5 | "jasmine-core": { 6 | "version": "2.4.1", 7 | "from": "jasmine-core@*", 8 | "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.4.1.tgz" 9 | }, 10 | "phantomjs-prebuilt": { 11 | "version": "2.1.5", 12 | "from": "phantomjs-prebuilt@>=1.9.0", 13 | "resolved": "https://registry.npmjs.org/phantomjs-prebuilt/-/phantomjs-prebuilt-2.1.5.tgz", 14 | "dependencies": { 15 | "adm-zip": { 16 | "version": "0.4.7", 17 | "from": "adm-zip@>=0.4.7 <0.5.0", 18 | "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.7.tgz" 19 | }, 20 | "fs-extra": { 21 | "version": "0.26.5", 22 | "from": "fs-extra@>=0.26.4 <0.27.0", 23 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.5.tgz", 24 | "dependencies": { 25 | "graceful-fs": { 26 | "version": "4.1.3", 27 | "from": "graceful-fs@>=4.1.2 <5.0.0", 28 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.3.tgz" 29 | }, 30 | "jsonfile": { 31 | "version": "2.2.3", 32 | "from": "jsonfile@>=2.1.0 <3.0.0", 33 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.2.3.tgz" 34 | }, 35 | "klaw": { 36 | "version": "1.1.3", 37 | "from": "klaw@>=1.0.0 <2.0.0", 38 | "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.1.3.tgz" 39 | }, 40 | "path-is-absolute": { 41 | "version": "1.0.0", 42 | "from": "path-is-absolute@>=1.0.0 <2.0.0", 43 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" 44 | }, 45 | "rimraf": { 46 | "version": "2.5.2", 47 | "from": "rimraf@>=2.2.8 <3.0.0", 48 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.2.tgz", 49 | "dependencies": { 50 | "glob": { 51 | "version": "7.0.3", 52 | "from": "glob@>=7.0.0 <8.0.0", 53 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.3.tgz", 54 | "dependencies": { 55 | "inflight": { 56 | "version": "1.0.4", 57 | "from": "inflight@>=1.0.4 <2.0.0", 58 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", 59 | "dependencies": { 60 | "wrappy": { 61 | "version": "1.0.1", 62 | "from": "wrappy@>=1.0.0 <2.0.0", 63 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 64 | } 65 | } 66 | }, 67 | "inherits": { 68 | "version": "2.0.1", 69 | "from": "inherits@>=2.0.0 <3.0.0", 70 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 71 | }, 72 | "minimatch": { 73 | "version": "3.0.0", 74 | "from": "minimatch@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0", 75 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.0.tgz", 76 | "dependencies": { 77 | "brace-expansion": { 78 | "version": "1.1.3", 79 | "from": "brace-expansion@>=1.0.0 <2.0.0", 80 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.3.tgz", 81 | "dependencies": { 82 | "balanced-match": { 83 | "version": "0.3.0", 84 | "from": "balanced-match@>=0.3.0 <0.4.0", 85 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.3.0.tgz" 86 | }, 87 | "concat-map": { 88 | "version": "0.0.1", 89 | "from": "concat-map@0.0.1", 90 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 91 | } 92 | } 93 | } 94 | } 95 | }, 96 | "once": { 97 | "version": "1.3.3", 98 | "from": "once@>=1.3.0 <2.0.0", 99 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", 100 | "dependencies": { 101 | "wrappy": { 102 | "version": "1.0.1", 103 | "from": "wrappy@>=1.0.0 <2.0.0", 104 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 105 | } 106 | } 107 | } 108 | } 109 | } 110 | } 111 | } 112 | } 113 | }, 114 | "hasha": { 115 | "version": "2.2.0", 116 | "from": "hasha@>=2.2.0 <3.0.0", 117 | "resolved": "https://registry.npmjs.org/hasha/-/hasha-2.2.0.tgz", 118 | "dependencies": { 119 | "is-stream": { 120 | "version": "1.0.1", 121 | "from": "is-stream@>=1.0.1 <2.0.0", 122 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.0.1.tgz" 123 | }, 124 | "pinkie-promise": { 125 | "version": "2.0.0", 126 | "from": "pinkie-promise@>=2.0.0 <3.0.0", 127 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz", 128 | "dependencies": { 129 | "pinkie": { 130 | "version": "2.0.4", 131 | "from": "pinkie@>=2.0.0 <3.0.0", 132 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" 133 | } 134 | } 135 | } 136 | } 137 | }, 138 | "kew": { 139 | "version": "0.7.0", 140 | "from": "kew@>=0.7.0 <0.8.0", 141 | "resolved": "https://registry.npmjs.org/kew/-/kew-0.7.0.tgz" 142 | }, 143 | "progress": { 144 | "version": "1.1.8", 145 | "from": "progress@>=1.1.8 <1.2.0", 146 | "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz" 147 | }, 148 | "request": { 149 | "version": "2.67.0", 150 | "from": "request@>=2.67.0 <2.68.0", 151 | "resolved": "https://registry.npmjs.org/request/-/request-2.67.0.tgz", 152 | "dependencies": { 153 | "bl": { 154 | "version": "1.0.3", 155 | "from": "bl@>=1.0.0 <1.1.0", 156 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.3.tgz", 157 | "dependencies": { 158 | "readable-stream": { 159 | "version": "2.0.5", 160 | "from": "readable-stream@>=2.0.5 <2.1.0", 161 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.5.tgz", 162 | "dependencies": { 163 | "core-util-is": { 164 | "version": "1.0.2", 165 | "from": "core-util-is@>=1.0.0 <1.1.0", 166 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" 167 | }, 168 | "inherits": { 169 | "version": "2.0.1", 170 | "from": "inherits@>=2.0.1 <2.1.0", 171 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 172 | }, 173 | "isarray": { 174 | "version": "0.0.1", 175 | "from": "isarray@0.0.1", 176 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 177 | }, 178 | "process-nextick-args": { 179 | "version": "1.0.6", 180 | "from": "process-nextick-args@>=1.0.6 <1.1.0", 181 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.6.tgz" 182 | }, 183 | "string_decoder": { 184 | "version": "0.10.31", 185 | "from": "string_decoder@>=0.10.0 <0.11.0", 186 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 187 | }, 188 | "util-deprecate": { 189 | "version": "1.0.2", 190 | "from": "util-deprecate@>=1.0.1 <1.1.0", 191 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" 192 | } 193 | } 194 | } 195 | } 196 | }, 197 | "caseless": { 198 | "version": "0.11.0", 199 | "from": "caseless@>=0.11.0 <0.12.0" 200 | }, 201 | "extend": { 202 | "version": "3.0.0", 203 | "from": "extend@>=3.0.0 <3.1.0" 204 | }, 205 | "forever-agent": { 206 | "version": "0.6.1", 207 | "from": "forever-agent@>=0.6.1 <0.7.0" 208 | }, 209 | "form-data": { 210 | "version": "1.0.0-rc3", 211 | "from": "form-data@>=1.0.0-rc3 <1.1.0", 212 | "dependencies": { 213 | "async": { 214 | "version": "1.5.2", 215 | "from": "async@>=1.4.0 <2.0.0", 216 | "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz" 217 | } 218 | } 219 | }, 220 | "json-stringify-safe": { 221 | "version": "5.0.1", 222 | "from": "json-stringify-safe@>=5.0.1 <5.1.0", 223 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" 224 | }, 225 | "mime-types": { 226 | "version": "2.1.10", 227 | "from": "mime-types@>=2.1.7 <2.2.0", 228 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.10.tgz", 229 | "dependencies": { 230 | "mime-db": { 231 | "version": "1.22.0", 232 | "from": "mime-db@>=1.22.0 <1.23.0", 233 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.22.0.tgz" 234 | } 235 | } 236 | }, 237 | "node-uuid": { 238 | "version": "1.4.7", 239 | "from": "node-uuid@>=1.4.7 <1.5.0", 240 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz" 241 | }, 242 | "qs": { 243 | "version": "5.2.0", 244 | "from": "qs@>=5.2.0 <5.3.0", 245 | "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz" 246 | }, 247 | "tunnel-agent": { 248 | "version": "0.4.2", 249 | "from": "tunnel-agent@>=0.4.1 <0.5.0", 250 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.2.tgz" 251 | }, 252 | "tough-cookie": { 253 | "version": "2.2.2", 254 | "from": "tough-cookie@>=2.2.0 <2.3.0", 255 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.2.2.tgz" 256 | }, 257 | "http-signature": { 258 | "version": "1.1.1", 259 | "from": "http-signature@>=1.1.0 <1.2.0", 260 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", 261 | "dependencies": { 262 | "assert-plus": { 263 | "version": "0.2.0", 264 | "from": "assert-plus@>=0.2.0 <0.3.0", 265 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz" 266 | }, 267 | "jsprim": { 268 | "version": "1.2.2", 269 | "from": "jsprim@>=1.2.2 <2.0.0", 270 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.2.2.tgz", 271 | "dependencies": { 272 | "extsprintf": { 273 | "version": "1.0.2", 274 | "from": "extsprintf@1.0.2", 275 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz" 276 | }, 277 | "json-schema": { 278 | "version": "0.2.2", 279 | "from": "json-schema@0.2.2", 280 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.2.tgz" 281 | }, 282 | "verror": { 283 | "version": "1.3.6", 284 | "from": "verror@1.3.6", 285 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz" 286 | } 287 | } 288 | }, 289 | "sshpk": { 290 | "version": "1.7.4", 291 | "from": "sshpk@>=1.7.0 <2.0.0", 292 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.7.4.tgz", 293 | "dependencies": { 294 | "asn1": { 295 | "version": "0.2.3", 296 | "from": "asn1@>=0.2.3 <0.3.0", 297 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz" 298 | }, 299 | "dashdash": { 300 | "version": "1.13.0", 301 | "from": "dashdash@>=1.10.1 <2.0.0", 302 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.13.0.tgz", 303 | "dependencies": { 304 | "assert-plus": { 305 | "version": "1.0.0", 306 | "from": "assert-plus@>=1.0.0 <2.0.0", 307 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" 308 | } 309 | } 310 | }, 311 | "jsbn": { 312 | "version": "0.1.0", 313 | "from": "jsbn@>=0.1.0 <0.2.0", 314 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz" 315 | }, 316 | "tweetnacl": { 317 | "version": "0.14.1", 318 | "from": "tweetnacl@>=0.13.0 <1.0.0", 319 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.1.tgz" 320 | }, 321 | "jodid25519": { 322 | "version": "1.0.2", 323 | "from": "jodid25519@>=1.0.0 <2.0.0", 324 | "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz" 325 | }, 326 | "ecc-jsbn": { 327 | "version": "0.1.1", 328 | "from": "ecc-jsbn@>=0.0.1 <1.0.0", 329 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz" 330 | } 331 | } 332 | } 333 | } 334 | }, 335 | "oauth-sign": { 336 | "version": "0.8.1", 337 | "from": "oauth-sign@>=0.8.0 <0.9.0", 338 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.1.tgz" 339 | }, 340 | "hawk": { 341 | "version": "3.1.3", 342 | "from": "hawk@>=3.1.0 <3.2.0", 343 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", 344 | "dependencies": { 345 | "hoek": { 346 | "version": "2.16.3", 347 | "from": "hoek@>=2.0.0 <3.0.0" 348 | }, 349 | "boom": { 350 | "version": "2.10.1", 351 | "from": "boom@>=2.0.0 <3.0.0", 352 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz" 353 | }, 354 | "cryptiles": { 355 | "version": "2.0.5", 356 | "from": "cryptiles@>=2.0.0 <3.0.0" 357 | }, 358 | "sntp": { 359 | "version": "1.0.9", 360 | "from": "sntp@>=1.0.0 <2.0.0" 361 | } 362 | } 363 | }, 364 | "aws-sign2": { 365 | "version": "0.6.0", 366 | "from": "aws-sign2@>=0.6.0 <0.7.0", 367 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz" 368 | }, 369 | "stringstream": { 370 | "version": "0.0.5", 371 | "from": "stringstream@>=0.0.4 <0.1.0", 372 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz" 373 | }, 374 | "combined-stream": { 375 | "version": "1.0.5", 376 | "from": "combined-stream@>=1.0.5 <1.1.0", 377 | "dependencies": { 378 | "delayed-stream": { 379 | "version": "1.0.0", 380 | "from": "delayed-stream@>=1.0.0 <1.1.0" 381 | } 382 | } 383 | }, 384 | "isstream": { 385 | "version": "0.1.2", 386 | "from": "isstream@>=0.1.2 <0.2.0" 387 | }, 388 | "is-typedarray": { 389 | "version": "1.0.0", 390 | "from": "is-typedarray@>=1.0.0 <1.1.0", 391 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" 392 | }, 393 | "har-validator": { 394 | "version": "2.0.6", 395 | "from": "har-validator@>=2.0.2 <2.1.0", 396 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", 397 | "dependencies": { 398 | "chalk": { 399 | "version": "1.1.1", 400 | "from": "chalk@>=1.1.1 <2.0.0", 401 | "dependencies": { 402 | "ansi-styles": { 403 | "version": "2.2.0", 404 | "from": "ansi-styles@>=2.1.0 <3.0.0", 405 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.0.tgz", 406 | "dependencies": { 407 | "color-convert": { 408 | "version": "1.0.0", 409 | "from": "color-convert@>=1.0.0 <2.0.0", 410 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.0.0.tgz" 411 | } 412 | } 413 | }, 414 | "escape-string-regexp": { 415 | "version": "1.0.5", 416 | "from": "escape-string-regexp@>=1.0.2 <2.0.0", 417 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" 418 | }, 419 | "has-ansi": { 420 | "version": "2.0.0", 421 | "from": "has-ansi@>=2.0.0 <3.0.0", 422 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 423 | "dependencies": { 424 | "ansi-regex": { 425 | "version": "2.0.0", 426 | "from": "ansi-regex@>=2.0.0 <3.0.0", 427 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" 428 | } 429 | } 430 | }, 431 | "strip-ansi": { 432 | "version": "3.0.1", 433 | "from": "strip-ansi@>=3.0.0 <4.0.0", 434 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 435 | "dependencies": { 436 | "ansi-regex": { 437 | "version": "2.0.0", 438 | "from": "ansi-regex@>=2.0.0 <3.0.0", 439 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" 440 | } 441 | } 442 | }, 443 | "supports-color": { 444 | "version": "2.0.0", 445 | "from": "supports-color@>=2.0.0 <3.0.0", 446 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" 447 | } 448 | } 449 | }, 450 | "commander": { 451 | "version": "2.9.0", 452 | "from": "commander@>=2.9.0 <3.0.0", 453 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", 454 | "dependencies": { 455 | "graceful-readlink": { 456 | "version": "1.0.1", 457 | "from": "graceful-readlink@>=1.0.0" 458 | } 459 | } 460 | }, 461 | "is-my-json-valid": { 462 | "version": "2.13.1", 463 | "from": "is-my-json-valid@>=2.12.4 <3.0.0", 464 | "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.13.1.tgz", 465 | "dependencies": { 466 | "generate-function": { 467 | "version": "2.0.0", 468 | "from": "generate-function@>=2.0.0 <3.0.0" 469 | }, 470 | "generate-object-property": { 471 | "version": "1.2.0", 472 | "from": "generate-object-property@>=1.1.0 <2.0.0", 473 | "dependencies": { 474 | "is-property": { 475 | "version": "1.0.2", 476 | "from": "is-property@>=1.0.0 <2.0.0" 477 | } 478 | } 479 | }, 480 | "jsonpointer": { 481 | "version": "2.0.0", 482 | "from": "jsonpointer@2.0.0", 483 | "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-2.0.0.tgz" 484 | }, 485 | "xtend": { 486 | "version": "4.0.1", 487 | "from": "xtend@>=4.0.0 <5.0.0", 488 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz" 489 | } 490 | } 491 | }, 492 | "pinkie-promise": { 493 | "version": "2.0.0", 494 | "from": "pinkie-promise@>=2.0.0 <3.0.0", 495 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.0.tgz", 496 | "dependencies": { 497 | "pinkie": { 498 | "version": "2.0.4", 499 | "from": "pinkie@>=2.0.0 <3.0.0", 500 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" 501 | } 502 | } 503 | } 504 | } 505 | } 506 | } 507 | }, 508 | "request-progress": { 509 | "version": "2.0.1", 510 | "from": "request-progress@>=2.0.1 <2.1.0", 511 | "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-2.0.1.tgz", 512 | "dependencies": { 513 | "throttleit": { 514 | "version": "1.0.0", 515 | "from": "throttleit@>=1.0.0 <2.0.0", 516 | "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz" 517 | } 518 | } 519 | }, 520 | "which": { 521 | "version": "1.2.4", 522 | "from": "which@>=1.2.2 <1.3.0", 523 | "resolved": "https://registry.npmjs.org/which/-/which-1.2.4.tgz", 524 | "dependencies": { 525 | "is-absolute": { 526 | "version": "0.1.7", 527 | "from": "is-absolute@>=0.1.7 <0.2.0", 528 | "dependencies": { 529 | "is-relative": { 530 | "version": "0.1.3", 531 | "from": "is-relative@>=0.1.0 <0.2.0" 532 | } 533 | } 534 | }, 535 | "isexe": { 536 | "version": "1.1.2", 537 | "from": "isexe@>=1.1.1 <2.0.0", 538 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz" 539 | } 540 | } 541 | } 542 | } 543 | }, 544 | "requirejs": { 545 | "version": "2.1.22", 546 | "from": "requirejs@>=2.1.0 <2.2.0", 547 | "resolved": "https://registry.npmjs.org/requirejs/-/requirejs-2.1.22.tgz" 548 | } 549 | } 550 | } 551 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-blocks", 3 | "description": "Template inheritance for Angular JS", 4 | "version": "0.1.10", 5 | "private": false, 6 | "homepage": "https://github.com/wmluke/angular-blocks", 7 | "author": { 8 | "name": "William L. Bunselmeyer", 9 | "email": "wmlukeb@gmail.com" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git://github.com/wmluke/angular-blocks.git" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/wmluke/angular-blocks/issues" 17 | }, 18 | "engines": { 19 | "node": ">= 4.2", 20 | "npm": "2.14.x" 21 | }, 22 | "scripts": { 23 | "test": "grunt test-phantom", 24 | "start": "node app", 25 | "coveralls": "cat ./reports/coverage/*/lcov.info | ./node_modules/coveralls/bin/coveralls.js" 26 | }, 27 | "devDependencies": { 28 | "grunt": "~0.4.1", 29 | "chai": "~3.5.0", 30 | "istanbul": "~0.4.2", 31 | "sinon-chai": "~2.8.0", 32 | "sinon": "~1.17.3", 33 | "matchdep": "~1.0.1", 34 | "jshint": "~2.9.1", 35 | "grunt-contrib-jshint": "~1.0.0", 36 | "grunt-contrib-concat": "~1.0.0", 37 | "grunt-contrib-uglify": "~1.0.0", 38 | "grunt-bumpup": "~0.6.3", 39 | "grunt-regarde": "~0.1.1", 40 | "grunt-exec": "~0.4.0", 41 | "grunt-build-lifecycle": "~0.1.1", 42 | "grunt-karma": "~0.12.1", 43 | "karma": "~0.13.22", 44 | "karma-ng-scenario": "~0.1.0", 45 | "karma-script-launcher": "~0.2.0", 46 | "karma-firefox-launcher": "~0.1.3", 47 | "karma-chrome-launcher": "~0.2.2", 48 | "karma-html2js-preprocessor": "~0.1.0", 49 | "karma-jasmine": "~0.3.7", 50 | "karma-requirejs": "~0.2.1", 51 | "karma-coffee-preprocessor": "~0.3.0", 52 | "karma-phantomjs-launcher": "~1.0.0", 53 | "karma-ng-html2js-preprocessor": "~0.2.1", 54 | "karma-junit-reporter": "~0.4.0", 55 | "karma-coverage": "~0.5.5", 56 | "coveralls": "~2.11.8" 57 | } 58 | } -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # angular-blocks 2 | 3 | [](https://travis-ci.org/wmluke/angular-blocks) 4 | [](https://coveralls.io/r/wmluke/angular-blocks?branch=master) 5 | 6 | Block style template inheritance for [AngularJS](http://angularjs.org) inspired by [Jade](http://jade-lang.com), [Handlebars](http://thejohnfreeman.com/blog/2012/03/23/template-inheritance-for-handlebars.html), and [Django](https://docs.djangoproject.com/en/dev/topics/templates/#template-inheritance). 7 | 8 | ## Installation 9 | 10 | Requires jquery. 11 | 12 | Download [angular-blocks.min.js](https://github.com/wmluke/angular-blocks/blob/master/dist/angular-blocks.min.js) or install with bower. 13 | 14 | ```bash 15 | $ bower install angular-blocks --save 16 | ``` 17 | 18 | Load `angular-blocks.min.js` then add the `angular-blocks` module to your Angular app. 19 | 20 | 21 | ```javascript 22 | angular.module('app', ['angular-blocks']); 23 | ``` 24 | 25 | ## Usage 26 | 27 | Given the template below: 28 | 29 | ```html 30 | 41 | ``` 42 | 43 | ### Block Replace: `data-block` 44 | 45 | ```html 46 |
Foo
49 |:header
59 |Foo
62 |Foo
75 |:header
85 |Foo
89 |:content
91 |Foo
104 |:header
114 |:content
117 |Foo
119 |Foo
133 |:header
143 |Foo
146 |:content
149 |Foo
162 |:header
172 |:content
175 |Foo
178 |{{ mainHeader }}
:content
{{ subHeader }}
{{ callCount }}
', 61 | ':sub-header
'); 73 | expect(element.find('[data-block="content"]').text().trim()).toBe('1'); 74 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 75 | })); 76 | }); 77 | 78 | describe('data-block directive', function () { 79 | it('should extend the content block', inject(function ($compile) { 80 | var html = [ 81 | '{{ foo }}
', 84 | ':header
'); 94 | expect(element.find('[data-block="content"]').html().trim()).toBe('Bar
'); 95 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 96 | })); 97 | 98 | it('should support multiple inheritance', inject(function ($compile) { 99 | var html = [ 100 | '{{ foo }}
', 103 | ':sub-header
'); 113 | expect(element.find('[data-block="content"]').html().trim()).toBe('Bar
'); 114 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 115 | })); 116 | 117 | it('should log a warning if the block is missing', inject(function ($compile, $log) { 118 | var html = [ 119 | '{{ foo }}
', 122 | ':header
'); 133 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 134 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 135 | })); 136 | }); 137 | 138 | describe('data-block-prepend directive', function () { 139 | it('should prepend the content block', inject(function ($compile) { 140 | var html = [ 141 | '{{ foo }}
:header
'); 152 | expect(element.find('[data-block="content"]').html().trim()).toBe('Bar
:content
'); 153 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 154 | })); 155 | 156 | it('should support multiple inheritance', inject(function ($compile) { 157 | var html = [ 158 | '{{ foo }}
:sub-header
'); 169 | expect(element.find('[data-block="content"]').html().trim()).toBe('Bar
:content
'); 170 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 171 | })); 172 | 173 | it('should log a warning if the block is missing', inject(function ($compile, $log) { 174 | var html = [ 175 | '{{ foo }}
:header
'); 187 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 188 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 189 | })); 190 | }); 191 | 192 | describe('data-block-append directive', function () { 193 | it('should prepend the content block', inject(function ($compile) { 194 | var html = [ 195 | '{{ foo }}
:header
'); 206 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
Bar
:footer
'); 208 | })); 209 | 210 | it('should support multiple inheritance', inject(function ($compile) { 211 | var html = [ 212 | '{{ foo }}
:sub-header
'); 223 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
Bar
:footer
'); 225 | })); 226 | 227 | it('should log a warning if the block is missing', inject(function ($compile, $log) { 228 | var html = [ 229 | '{{ foo }}
:header
'); 241 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 242 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 243 | })); 244 | }); 245 | 246 | 247 | describe('data-block-before directive', function () { 248 | it('should prepend the content block', inject(function ($compile) { 249 | var html = [ 250 | '{{ foo }}
:header
'); 261 | expect(element.find('[data-block="content"]').prev().html().trim()).toBe('Bar
'); 262 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 263 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 264 | })); 265 | 266 | it('should support multiple inheritance', inject(function ($compile) { 267 | var html = [ 268 | '{{ foo }}
:sub-header
'); 279 | expect(element.find('[data-block="content"]').prev().html().trim()).toBe('Bar
'); 280 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 281 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 282 | })); 283 | 284 | it('should log a warning if the block is missing', inject(function ($compile, $log) { 285 | var html = [ 286 | '{{ foo }}
:header
'); 298 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 299 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 300 | })); 301 | }); 302 | 303 | describe('data-block-after directive', function () { 304 | it('should prepend the content block', inject(function ($compile) { 305 | var html = [ 306 | '{{ foo }}
:header
'); 317 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 318 | expect(element.find('[data-block="content"]').next().html().trim()).toBe('Bar
'); 319 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 320 | })); 321 | 322 | it('should prepend the content block', inject(function ($compile) { 323 | var html = [ 324 | '{{ foo }}
:sub-header
'); 335 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 336 | expect(element.find('[data-block="content"]').next().html().trim()).toBe('Bar
'); 337 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 338 | })); 339 | 340 | it('should log a warning if the block is missing', inject(function ($compile, $log) { 341 | var html = [ 342 | '{{ foo }}
:header
'); 354 | expect(element.find('[data-block="content"]').html().trim()).toBe(':content
'); 355 | expect(element.find('[data-block="footer"]').html().trim()).toBe(':footer
'); 356 | })); 357 | }); 358 | 359 | }); 360 | --------------------------------------------------------------------------------