From e083d56229203a985d1b7d9b02ddb23e28d8c7f5 Mon Sep 17 00:00:00 2001 From: Mateusz Bilski Date: Sat, 17 Nov 2012 15:53:47 +0100 Subject: [PATCH 1/3] Update README.md --- README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 43b6884..d6a0f75 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,12 @@ angularjs-requirejs-lazy-controllers ==================================== -Modified AngularJS' ngView and ngController directives to enable support for lazy loading of controllers using RequireJS. \ No newline at end of file +Modified AngularJS' ngView and ngController directives to enable support for lazy loading of controllers using RequireJS. + +My custom directives are: + +mb-lazy-controller-view - this is a modified version of Angular's ng-view, when you specify controllerModule property in your routes +it will load the module (with the controller) using require and apply it to the partial + +mb-lazy-controller - when used as an attribute will load specified module (with the controller) using require and apply it to the element, like the ng-controller normally does. +It can be used within the partial, but only with mb-lazy-controller-view From ddc80f1e47720075c639313d6469749fc0ca048c Mon Sep 17 00:00:00 2001 From: Mateusz Bilski Date: Tue, 20 Nov 2012 20:59:36 +0100 Subject: [PATCH 2/3] New implementation using promises, now loads template and controller in paraller, removed old custom directives --- app/css/app.css | 4 + app/index.html | 8 +- app/js/controllers/first.js | 18 +- app/js/controllers/second.js | 19 +- app/js/controllers/third.js | 31 - app/js/directives.js | 109 - app/js/main.js | 3 +- app/js/routes.js | 43 +- app/lib/angular/angular-bootstrap-prettify.js | 1833 +++++++++++++++++ app/lib/angular/angular-bootstrap.js | 166 ++ app/lib/angular/version.txt | 2 +- app/lib/{requirejs => require}/require.js | 0 app/lib/require/text.js | 309 +++ app/partials/view1.html | 4 +- 14 files changed, 2360 insertions(+), 189 deletions(-) delete mode 100644 app/js/controllers/third.js delete mode 100644 app/js/directives.js create mode 100644 app/lib/angular/angular-bootstrap-prettify.js create mode 100644 app/lib/angular/angular-bootstrap.js rename app/lib/{requirejs => require}/require.js (100%) create mode 100644 app/lib/require/text.js diff --git a/app/css/app.css b/app/css/app.css index 4aeb659..afce8ab 100644 --- a/app/css/app.css +++ b/app/css/app.css @@ -1,2 +1,6 @@ /* app css stylesheet */ +body { + padding-left: 20px; + padding-top: 20px; +} diff --git a/app/index.html b/app/index.html index 3140f9c..c423a55 100644 --- a/app/index.html +++ b/app/index.html @@ -13,12 +13,8 @@ view2 -
+
-
-

{{message}}

-
- - + diff --git a/app/js/controllers/first.js b/app/js/controllers/first.js index 39c411b..af3d151 100644 --- a/app/js/controllers/first.js +++ b/app/js/controllers/first.js @@ -7,23 +7,11 @@ 'use strict'; -define(['app'], function (app) { +define([], function () { - var FirstController = function ($scope, $timeout) { - var message = "I'm the 1st controller! random: "; - $scope.message = message; - - function update() { - $scope.message = message + Math.random(); - $timeout(update, 1000); - } - - update(); + function FirstController($scope) { + $scope.message = "I'm the 1st controller!"; } - FirstController.$inject = ['$scope', '$timeout']; - - app.controller('FirstController', FirstController); - return FirstController; }); \ No newline at end of file diff --git a/app/js/controllers/second.js b/app/js/controllers/second.js index d68a16b..d20e40e 100644 --- a/app/js/controllers/second.js +++ b/app/js/controllers/second.js @@ -7,24 +7,11 @@ 'use strict'; -define(['app'], function (app) { +define([], function () { - var SecondController = function ($scope, $timeout) { - var message = "I'm the 2nd controller! random: "; - - $scope.message = message; - - function update() { - $scope.message = message + Math.random(); - $timeout(update, 1000); - } - - update(); + function SecondController($scope) { + $scope.message = "I'm the 2nd controller!"; } - SecondController.$inject = ['$scope', '$timeout']; - - app.controller('SecondController', SecondController); - return SecondController; }); diff --git a/app/js/controllers/third.js b/app/js/controllers/third.js deleted file mode 100644 index e40ce22..0000000 --- a/app/js/controllers/third.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Created with IntelliJ IDEA. - * User: Mateusz - * Date: 17.11.12 - * Time: 15:24 - */ - -'use strict'; - -define(['app'], function (app) { - - var SecondController = function ($scope, $timeout) { - $scope.message = message; - - var message = "I'm the 3rd controller! random: "; - - function update() { - $scope.message = message + Math.random(); - $timeout(update, 1000); - } - - update(); - } - - SecondController.$inject = ['$scope', '$timeout']; - - app.controller('ThirdController', SecondController); - - return SecondController; -}); - diff --git a/app/js/directives.js b/app/js/directives.js deleted file mode 100644 index 715bf88..0000000 --- a/app/js/directives.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * Created with IntelliJ IDEA. - * User: Mateusz - * Date: 16.11.12 - * Time: 21:28 - */ -'use strict'; - -define(['app'], function (app) { - - app.directive('mbLazyController', ['$controller', '$compile', function ($controller, $compile) { - return { - restrict:'A', - scope:true, - link:function (scope, element, attr) { - var controller, - locals = {$scope:scope}, - controllerModule = attr.mbLazyController, - onLoadExp = attr.onload || ''; - - require([controllerModule], function (constructor) { - controller = $controller(constructor, locals); - element.contents().data('$ngControllerController', controller); - $compile(element.contents())(scope); - scope.$apply(); - scope.$emit('$viewContentLoaded'); - scope.$eval(onLoadExp); - }) - } - }; - }]); - - app.directive('mbLazyControllerView', - ['$http', '$templateCache', '$route', '$anchorScroll', '$compile', '$controller', - function ($http, $templateCache, $route, $anchorScroll, $compile, $controller) { - return { - restrict:'ECA', - terminal:true, - link:function (scope, element, attr) { - var lastScope, - onLoadExp = attr.onload || ''; - - scope.$on('$routeChangeSuccess', update); - update(); - - - function destroyLastScope() { - if (lastScope) { - lastScope.$destroy(); - lastScope = null; - } - } - - function clearContent() { - element.html(''); - destroyLastScope(); - } - - function update() { - var locals = $route.current && $route.current.locals, - template = locals && locals.$template; - - if (template) { - destroyLastScope(); - - var current = $route.current, - controller; - - lastScope = current.scope = scope.$new(); - locals.$scope = lastScope; - - if (current.controller) { - element.html(template); - controller = $controller(current.controller, locals); - complete(lastScope, controller); - } else if (current.controllerModule) { - require([current.controllerModule], function (controllerConstructor) { - element.html(template); - controller = $controller(controllerConstructor, locals); - complete(lastScope, controller); - lastScope.$apply(); - }); - } else { - element.html(template); - $compile(element.contents())(lastScope); - } - - - } else { - clearContent(); - } - } - - function complete(scope, controller) { - element.contents().data('$ngControllerController', controller); - $compile(element.contents())(scope); - scope.$emit('$viewContentLoaded'); - scope.$eval(onLoadExp); - - // $anchorScroll might listen on event... - $anchorScroll(); - } - } - }; - }]); - - - return app; -}); diff --git a/app/js/main.js b/app/js/main.js index 2de7085..2c01aac 100644 --- a/app/js/main.js +++ b/app/js/main.js @@ -10,6 +10,7 @@ require.config({ baseUrl:'js', paths:{ + text:'../lib/require/text', jquery:'../lib/jquery/jquery', angular:'../lib/angular/angular' }, @@ -26,9 +27,9 @@ require.config({ require([ 'angular', + 'text', 'jquery', 'app', - 'directives', 'routes' ], function (angular) { //This function will be called when all the dependencies diff --git a/app/js/routes.js b/app/js/routes.js index 17e5b94..5c5e539 100644 --- a/app/js/routes.js +++ b/app/js/routes.js @@ -9,14 +9,41 @@ define(['app'], function (app) { - return app.config(function ($routeProvider) { - $routeProvider.when('/view1', { - templateUrl:'partials/view1.html' - }); - $routeProvider.when('/view2', { - templateUrl:'partials/view2.html', - controllerModule:'controllers/second' - }); + function viewConfig(controllerProvider, controllerName, templateUrl) { + var defer, + html, + routeDefinition = {}; + + routeDefinition.template = function () { + return html; + }; + routeDefinition.controller = controllerName; + routeDefinition.resolve = { + delay:function ($q, $rootScope) { + defer = $q.defer(); + if (!routeDefinition.html) { + + require([controllerName, "text!" + templateUrl], function (controller, template) { + controllerProvider.register(controllerName, controller); + html = template; + defer.resolve(true); + $rootScope.$apply() + }) + + } else { + defer.resolve(true); + } + return defer.promise; + } + } + + return routeDefinition; + } + + return app.config(function ($routeProvider, $controllerProvider) { + $routeProvider.when('/view1', viewConfig($controllerProvider, 'controllers/first', '../partials/view1.html')); + $routeProvider.when('/view2', viewConfig($controllerProvider, 'controllers/second', '../partials/view2.html')); + $routeProvider.otherwise({redirectTo:'/view1'}); }); diff --git a/app/lib/angular/angular-bootstrap-prettify.js b/app/lib/angular/angular-bootstrap-prettify.js new file mode 100644 index 0000000..d2763f4 --- /dev/null +++ b/app/lib/angular/angular-bootstrap-prettify.js @@ -0,0 +1,1833 @@ +/** + * @license AngularJS v1.1.1-af7e0bd0 + * (c) 2010-2012 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) { +'use strict'; + +var directive = {}; +var service = { value: {} }; + +var DEPENDENCIES = { + 'angular.js': 'http://code.angularjs.org/angular-' + angular.version.full + '.min.js', + 'angular-resource.js': 'http://code.angularjs.org/angular-resource-' + angular.version.full + '.min.js', + 'angular-sanitize.js': 'http://code.angularjs.org/angular-sanitize-' + angular.version.full + '.min.js', + 'angular-cookies.js': 'http://code.angularjs.org/angular-cookies-' + angular.version.full + '.min.js' +}; + + +function escape(text) { + return text. + replace(/\&/g, '&'). + replace(/\/g, '>'). + replace(/"/g, '"'); +} + +/** + * http://stackoverflow.com/questions/451486/pre-tag-loses-line-breaks-when-setting-innerhtml-in-ie + * http://stackoverflow.com/questions/195363/inserting-a-newline-into-a-pre-tag-ie-javascript + */ +function setHtmlIe8SafeWay(element, html) { + var newElement = angular.element('
' + html + '
'); + + element.html(''); + element.append(newElement.contents()); + return element; +} + + +directive.jsFiddle = function(getEmbeddedTemplate, escape, script) { + return { + terminal: true, + link: function(scope, element, attr) { + var name = '', + stylesheet = '\n', + fields = { + html: '', + css: '', + js: '' + }; + + angular.forEach(attr.jsFiddle.split(' '), function(file, index) { + var fileType = file.split('.')[1]; + + if (fileType == 'html') { + if (index == 0) { + fields[fileType] += + '
\n' + + getEmbeddedTemplate(file, 2); + } else { + fields[fileType] += '\n\n\n \n' + + ' \n'; + } + } else { + fields[fileType] += getEmbeddedTemplate(file) + '\n'; + } + }); + + fields.html += '
\n'; + + setHtmlIe8SafeWay(element, + '
' + + hiddenField('title', 'AngularJS Example: ' + name) + + hiddenField('css', ' \n' + + stylesheet + + script.angular + + (attr.resource ? script.resource : '') + + ''); \ No newline at end of file diff --git a/app/lib/angular/angular-bootstrap.js b/app/lib/angular/angular-bootstrap.js new file mode 100644 index 0000000..02fcdfb --- /dev/null +++ b/app/lib/angular/angular-bootstrap.js @@ -0,0 +1,166 @@ +/** + * @license AngularJS v1.1.1-af7e0bd0 + * (c) 2010-2012 Google, Inc. http://angularjs.org + * License: MIT + */ +(function(window, angular, undefined) { +'use strict'; + +var directive = {}; + +directive.dropdownToggle = + ['$document', '$location', '$window', + function ($document, $location, $window) { + var openElement = null, close; + return { + restrict: 'C', + link: function(scope, element, attrs) { + scope.$watch(function dropdownTogglePathWatch(){return $location.path();}, function dropdownTogglePathWatchAction() { + close && close(); + }); + + element.parent().bind('click', function(event) { + close && close(); + }); + + element.bind('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + + var iWasOpen = false; + + if (openElement) { + iWasOpen = openElement === element; + close(); + } + + if (!iWasOpen){ + element.parent().addClass('open'); + openElement = element; + + close = function (event) { + event && event.preventDefault(); + event && event.stopPropagation(); + $document.unbind('click', close); + element.parent().removeClass('open'); + close = null; + openElement = null; + } + + $document.bind('click', close); + } + }); + } + }; + }]; + + +directive.tabbable = function() { + return { + restrict: 'C', + compile: function(element) { + var navTabs = angular.element(''), + tabContent = angular.element('
'); + + tabContent.append(element.contents()); + element.append(navTabs).append(tabContent); + }, + controller: ['$scope', '$element', function($scope, $element) { + var navTabs = $element.contents().eq(0), + ngModel = $element.controller('ngModel') || {}, + tabs = [], + selectedTab; + + ngModel.$render = function() { + var $viewValue = this.$viewValue; + + if (selectedTab ? (selectedTab.value != $viewValue) : $viewValue) { + if(selectedTab) { + selectedTab.paneElement.removeClass('active'); + selectedTab.tabElement.removeClass('active'); + selectedTab = null; + } + if($viewValue) { + for(var i = 0, ii = tabs.length; i < ii; i++) { + if ($viewValue == tabs[i].value) { + selectedTab = tabs[i]; + break; + } + } + if (selectedTab) { + selectedTab.paneElement.addClass('active'); + selectedTab.tabElement.addClass('active'); + } + } + + } + }; + + this.addPane = function(element, attr) { + var li = angular.element('
  • '), + a = li.find('a'), + tab = { + paneElement: element, + paneAttrs: attr, + tabElement: li + }; + + tabs.push(tab); + + attr.$observe('value', update)(); + attr.$observe('title', function(){ update(); a.text(tab.title); })(); + + function update() { + tab.title = attr.title; + tab.value = attr.value || attr.title; + if (!ngModel.$setViewValue && (!ngModel.$viewValue || tab == selectedTab)) { + // we are not part of angular + ngModel.$viewValue = tab.value; + } + ngModel.$render(); + } + + navTabs.append(li); + li.bind('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + if (ngModel.$setViewValue) { + $scope.$apply(function() { + ngModel.$setViewValue(tab.value); + ngModel.$render(); + }); + } else { + // we are not part of angular + ngModel.$viewValue = tab.value; + ngModel.$render(); + } + }); + + return function() { + tab.tabElement.remove(); + for(var i = 0, ii = tabs.length; i < ii; i++ ) { + if (tab == tabs[i]) { + tabs.splice(i, 1); + } + } + }; + } + }] + }; +}; + + +directive.tabPane = function() { + return { + require: '^tabbable', + restrict: 'C', + link: function(scope, element, attrs, tabsCtrl) { + element.bind('$remove', tabsCtrl.addPane(element, attrs)); + } + }; +}; + + +angular.module('bootstrap', []).directive(directive); + +})(window, window.angular); diff --git a/app/lib/angular/version.txt b/app/lib/angular/version.txt index 6d7de6e..81021b1 100644 --- a/app/lib/angular/version.txt +++ b/app/lib/angular/version.txt @@ -1 +1 @@ -1.0.2 +1.1.1-af7e0bd0 diff --git a/app/lib/requirejs/require.js b/app/lib/require/require.js similarity index 100% rename from app/lib/requirejs/require.js rename to app/lib/require/require.js diff --git a/app/lib/require/text.js b/app/lib/require/text.js new file mode 100644 index 0000000..304aab3 --- /dev/null +++ b/app/lib/require/text.js @@ -0,0 +1,309 @@ +/** + * @license RequireJS text 2.0.3 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/requirejs/text for details + */ +/*jslint regexp: true */ +/*global require: false, XMLHttpRequest: false, ActiveXObject: false, + define: false, window: false, process: false, Packages: false, + java: false, location: false */ + +define(['module'], function (module) { + 'use strict'; + + var text, fs, + progIds = ['Msxml2.XMLHTTP', 'Microsoft.XMLHTTP', 'Msxml2.XMLHTTP.4.0'], + xmlRegExp = /^\s*<\?xml(\s)+version=[\'\"](\d)*.(\d)*[\'\"](\s)*\?>/im, + bodyRegExp = /]*>\s*([\s\S]+)\s*<\/body>/im, + hasLocation = typeof location !== 'undefined' && location.href, + defaultProtocol = hasLocation && location.protocol && location.protocol.replace(/\:/, ''), + defaultHostName = hasLocation && location.hostname, + defaultPort = hasLocation && (location.port || undefined), + buildMap = [], + masterConfig = (module.config && module.config()) || {}; + + text = { + version: '2.0.3', + + strip: function (content) { + //Strips declarations so that external SVG and XML + //documents can be added to a document without worry. Also, if the string + //is an HTML document, only the part inside the body tag is returned. + if (content) { + content = content.replace(xmlRegExp, ""); + var matches = content.match(bodyRegExp); + if (matches) { + content = matches[1]; + } + } else { + content = ""; + } + return content; + }, + + jsEscape: function (content) { + return content.replace(/(['\\])/g, '\\$1') + .replace(/[\f]/g, "\\f") + .replace(/[\b]/g, "\\b") + .replace(/[\n]/g, "\\n") + .replace(/[\t]/g, "\\t") + .replace(/[\r]/g, "\\r") + .replace(/[\u2028]/g, "\\u2028") + .replace(/[\u2029]/g, "\\u2029"); + }, + + createXhr: masterConfig.createXhr || function () { + //Would love to dump the ActiveX crap in here. Need IE 6 to die first. + var xhr, i, progId; + if (typeof XMLHttpRequest !== "undefined") { + return new XMLHttpRequest(); + } else if (typeof ActiveXObject !== "undefined") { + for (i = 0; i < 3; i += 1) { + progId = progIds[i]; + try { + xhr = new ActiveXObject(progId); + } catch (e) {} + + if (xhr) { + progIds = [progId]; // so faster next time + break; + } + } + } + + return xhr; + }, + + /** + * Parses a resource name into its component parts. Resource names + * look like: module/name.ext!strip, where the !strip part is + * optional. + * @param {String} name the resource name + * @returns {Object} with properties "moduleName", "ext" and "strip" + * where strip is a boolean. + */ + parseName: function (name) { + var strip = false, index = name.indexOf("."), + modName = name.substring(0, index), + ext = name.substring(index + 1, name.length); + + index = ext.indexOf("!"); + if (index !== -1) { + //Pull off the strip arg. + strip = ext.substring(index + 1, ext.length); + strip = strip === "strip"; + ext = ext.substring(0, index); + } + + return { + moduleName: modName, + ext: ext, + strip: strip + }; + }, + + xdRegExp: /^((\w+)\:)?\/\/([^\/\\]+)/, + + /** + * Is an URL on another domain. Only works for browser use, returns + * false in non-browser environments. Only used to know if an + * optimized .js version of a text resource should be loaded + * instead. + * @param {String} url + * @returns Boolean + */ + useXhr: function (url, protocol, hostname, port) { + var uProtocol, uHostName, uPort, + match = text.xdRegExp.exec(url); + if (!match) { + return true; + } + uProtocol = match[2]; + uHostName = match[3]; + + uHostName = uHostName.split(':'); + uPort = uHostName[1]; + uHostName = uHostName[0]; + + return (!uProtocol || uProtocol === protocol) && + (!uHostName || uHostName.toLowerCase() === hostname.toLowerCase()) && + ((!uPort && !uHostName) || uPort === port); + }, + + finishLoad: function (name, strip, content, onLoad) { + content = strip ? text.strip(content) : content; + if (masterConfig.isBuild) { + buildMap[name] = content; + } + onLoad(content); + }, + + load: function (name, req, onLoad, config) { + //Name has format: some.module.filext!strip + //The strip part is optional. + //if strip is present, then that means only get the string contents + //inside a body tag in an HTML string. For XML/SVG content it means + //removing the declarations so the content can be inserted + //into the current doc without problems. + + // Do not bother with the work if a build and text will + // not be inlined. + if (config.isBuild && !config.inlineText) { + onLoad(); + return; + } + + masterConfig.isBuild = config.isBuild; + + var parsed = text.parseName(name), + nonStripName = parsed.moduleName + '.' + parsed.ext, + url = req.toUrl(nonStripName), + useXhr = (masterConfig.useXhr) || + text.useXhr; + + //Load the text. Use XHR if possible and in a browser. + if (!hasLocation || useXhr(url, defaultProtocol, defaultHostName, defaultPort)) { + text.get(url, function (content) { + text.finishLoad(name, parsed.strip, content, onLoad); + }, function (err) { + if (onLoad.error) { + onLoad.error(err); + } + }); + } else { + //Need to fetch the resource across domains. Assume + //the resource has been optimized into a JS module. Fetch + //by the module name + extension, but do not include the + //!strip part to avoid file system issues. + req([nonStripName], function (content) { + text.finishLoad(parsed.moduleName + '.' + parsed.ext, + parsed.strip, content, onLoad); + }); + } + }, + + write: function (pluginName, moduleName, write, config) { + if (buildMap.hasOwnProperty(moduleName)) { + var content = text.jsEscape(buildMap[moduleName]); + write.asModule(pluginName + "!" + moduleName, + "define(function () { return '" + + content + + "';});\n"); + } + }, + + writeFile: function (pluginName, moduleName, req, write, config) { + var parsed = text.parseName(moduleName), + nonStripName = parsed.moduleName + '.' + parsed.ext, + //Use a '.js' file name so that it indicates it is a + //script that can be loaded across domains. + fileName = req.toUrl(parsed.moduleName + '.' + + parsed.ext) + '.js'; + + //Leverage own load() method to load plugin value, but only + //write out values that do not have the strip argument, + //to avoid any potential issues with ! in file names. + text.load(nonStripName, req, function (value) { + //Use own write() method to construct full module value. + //But need to create shell that translates writeFile's + //write() to the right interface. + var textWrite = function (contents) { + return write(fileName, contents); + }; + textWrite.asModule = function (moduleName, contents) { + return write.asModule(moduleName, fileName, contents); + }; + + text.write(pluginName, nonStripName, textWrite, config); + }, config); + } + }; + + if (masterConfig.env === 'node' || (!masterConfig.env && + typeof process !== "undefined" && + process.versions && + !!process.versions.node)) { + //Using special require.nodeRequire, something added by r.js. + fs = require.nodeRequire('fs'); + + text.get = function (url, callback) { + var file = fs.readFileSync(url, 'utf8'); + //Remove BOM (Byte Mark Order) from utf8 files if it is there. + if (file.indexOf('\uFEFF') === 0) { + file = file.substring(1); + } + callback(file); + }; + } else if (masterConfig.env === 'xhr' || (!masterConfig.env && + text.createXhr())) { + text.get = function (url, callback, errback) { + var xhr = text.createXhr(); + xhr.open('GET', url, true); + + //Allow overrides specified in config + if (masterConfig.onXhr) { + masterConfig.onXhr(xhr, url); + } + + xhr.onreadystatechange = function (evt) { + var status, err; + //Do not explicitly handle errors, those should be + //visible via console output in the browser. + if (xhr.readyState === 4) { + status = xhr.status; + if (status > 399 && status < 600) { + //An http 4xx or 5xx error. Signal an error. + err = new Error(url + ' HTTP status: ' + status); + err.xhr = xhr; + errback(err); + } else { + callback(xhr.responseText); + } + } + }; + xhr.send(null); + }; + } else if (masterConfig.env === 'rhino' || (!masterConfig.env && + typeof Packages !== 'undefined' && typeof java !== 'undefined')) { + //Why Java, why is this so awkward? + text.get = function (url, callback) { + var stringBuffer, line, + encoding = "utf-8", + file = new java.io.File(url), + lineSeparator = java.lang.System.getProperty("line.separator"), + input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), encoding)), + content = ''; + try { + stringBuffer = new java.lang.StringBuffer(); + line = input.readLine(); + + // Byte Order Mark (BOM) - The Unicode Standard, version 3.0, page 324 + // http://www.unicode.org/faq/utf_bom.html + + // Note that when we use utf-8, the BOM should appear as "EF BB BF", but it doesn't due to this bug in the JDK: + // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4508058 + if (line && line.length() && line.charAt(0) === 0xfeff) { + // Eat the BOM, since we've already found the encoding on this file, + // and we plan to concatenating this buffer with others; the BOM should + // only appear at the top of a file. + line = line.substring(1); + } + + stringBuffer.append(line); + + while ((line = input.readLine()) !== null) { + stringBuffer.append(lineSeparator); + stringBuffer.append(line); + } + //Make sure we return a JavaScript string and not a Java string. + content = String(stringBuffer.toString()); //String + } finally { + input.close(); + } + callback(content); + }; + } + + return text; +}); + diff --git a/app/partials/view1.html b/app/partials/view1.html index 6c71b92..92257b3 100644 --- a/app/partials/view1.html +++ b/app/partials/view1.html @@ -1,3 +1,3 @@ -
    -

    {{message}}

    +
    +

    {{message}}

    From ef03afbc62b41811d9b0802b03e6e4365fc6ce2a Mon Sep 17 00:00:00 2001 From: Mateusz Bilski Date: Thu, 22 Nov 2012 23:23:39 +0100 Subject: [PATCH 3/3] Implemented lazy directives, refactored --- README.md | 25 ++++++++--- app/js/app.js | 8 +++- app/js/directives/version.js | 17 ++++++++ app/js/routes.js | 39 ++---------------- app/js/utils/lazy-directives.js | 27 ++++++++++++ app/js/utils/route-config.js | 73 +++++++++++++++++++++++++++++++++ app/partials/view2.html | 1 + 7 files changed, 147 insertions(+), 43 deletions(-) create mode 100644 app/js/directives/version.js create mode 100644 app/js/utils/lazy-directives.js create mode 100644 app/js/utils/route-config.js diff --git a/README.md b/README.md index 99e3958..27a6bc5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ angularjs-requirejs-lazy-controllers ==================================== -Routes configuration that loads both template and controller using RequireJS. Files are loaded (in parallel) +Routes configuration that loads template, controller and directives using RequireJS. Files are loaded (in parallel) when user changes the location and are displayed in Angular's ngView. ## Used libs @@ -12,13 +12,26 @@ when user changes the location and are displayed in Angular's ngView. ## Usage +### app.js + ```javascript -app.config(function ($routeProvider, $controllerProvider) { - $routeProvider.when('/view1', routeConfig($controllerProvider, 'controllers/first', '../partials/view1.html')); - $routeProvider.when('/view2', routeConfig($controllerProvider, 'controllers/second', '../partials/view2.html')); - $routeProvider.otherwise({redirectTo:'/view1'}); - }); + return angular.module('myApp', [], function ($compileProvider, $controllerProvider) { + routeConfig.setCompileProvider($compileProvider); + routeConfig.setControllerProvider($controllerProvider); + }) +``` + +### routes.js + +```javascript + + return app.config(function ($routeProvider) { + $routeProvider.when('/view1', routeConfig.config('../partials/view1.html', 'controllers/first')); + $routeProvider.when('/view2', routeConfig.config('../partials/view2.html', 'controllers/second', ['directives/version'])); + + $routeProvider.otherwise({redirectTo:'/view1'}); + }); ``` ## License diff --git a/app/js/app.js b/app/js/app.js index b65c064..429e554 100644 --- a/app/js/app.js +++ b/app/js/app.js @@ -6,6 +6,10 @@ */ 'use strict'; -define(['angular'], function (angular) { - return angular.module('myApp', []); +define(['angular', 'utils/route-config'], function (angular, routeConfig, lazyDirectives) { + + return angular.module('myApp', [], function ($compileProvider, $controllerProvider) { + routeConfig.setCompileProvider($compileProvider); + routeConfig.setControllerProvider($controllerProvider); + }) }); diff --git a/app/js/directives/version.js b/app/js/directives/version.js new file mode 100644 index 0000000..1f117ac --- /dev/null +++ b/app/js/directives/version.js @@ -0,0 +1,17 @@ +/** + * Created with IntelliJ IDEA. + * User: Mateusz + * Date: 22.11.12 + * Time: 22:04 + */ + +'use strict'; + +define([], function () { + + return ['appVersion', function () { + return function (scope, elm, attrs) { + elm.text("1.0.0"); + } + }] +}) \ No newline at end of file diff --git a/app/js/routes.js b/app/js/routes.js index bf55fb8..5bd14b7 100644 --- a/app/js/routes.js +++ b/app/js/routes.js @@ -7,42 +7,11 @@ 'use strict'; -define(['app'], function (app) { +define(['app', 'utils/route-config'], function (app, routeConfig) { - function routeConfig(controllerProvider, controllerName, templateUrl) { - var defer, - html, - routeDefinition = {}; - - routeDefinition.template = function () { - return html; - }; - routeDefinition.controller = controllerName; - routeDefinition.resolve = { - delay:function ($q, $rootScope) { - defer = $q.defer(); - if (!routeDefinition.html) { - - require([controllerName, "text!" + templateUrl], function (controller, template) { - controllerProvider.register(controllerName, controller); - html = template; - defer.resolve(true); - $rootScope.$apply() - }) - - } else { - defer.resolve(true); - } - return defer.promise; - } - } - - return routeDefinition; - } - - return app.config(function ($routeProvider, $controllerProvider) { - $routeProvider.when('/view1', routeConfig($controllerProvider, 'controllers/first', '../partials/view1.html')); - $routeProvider.when('/view2', routeConfig($controllerProvider, 'controllers/second', '../partials/view2.html')); + return app.config(function ($routeProvider) { + $routeProvider.when('/view1', routeConfig.config('../partials/view1.html', 'controllers/first')); + $routeProvider.when('/view2', routeConfig.config('../partials/view2.html', 'controllers/second', ['directives/version'])); $routeProvider.otherwise({redirectTo:'/view1'}); }); diff --git a/app/js/utils/lazy-directives.js b/app/js/utils/lazy-directives.js new file mode 100644 index 0000000..26f110e --- /dev/null +++ b/app/js/utils/lazy-directives.js @@ -0,0 +1,27 @@ +/** + * Created with IntelliJ IDEA. + * User: Mateusz + * Date: 22.11.12 + * Time: 22:08 + */ + +define([], function () { + + var $compileProvider; + + function setCompileProvider(value) { + $compileProvider = value; + } + + function register(directive) { + if (!$compileProvider) { + throw new Error("$compileProvider is not set!"); + } + $compileProvider.directive.apply(null, directive); + } + + return { + setCompileProvider:setCompileProvider, + register:register + } +}) diff --git a/app/js/utils/route-config.js b/app/js/utils/route-config.js new file mode 100644 index 0000000..b86c340 --- /dev/null +++ b/app/js/utils/route-config.js @@ -0,0 +1,73 @@ +/** + * Created with IntelliJ IDEA. + * User: Mateusz + * Date: 22.11.12 + * Time: 22:38 + */ + +define(['utils/lazy-directives'], function (lazyDirectives) { + + var $controllerProvider, + $compileProvider; + + function setControllerProvider(value) { + $controllerProvider = value; + } + + function setCompileProvider(value) { + $compileProvider = value; + lazyDirectives.setCompileProvider(value); + } + + function config(templateUrl, controllerName, directives) { + if (!$controllerProvider) { + throw new Error("$controllerProvider is not set!"); + } + + var defer, + html, + routeDefinition = {}; + + routeDefinition.template = function () { + return html; + }; + routeDefinition.controller = controllerName; + routeDefinition.resolve = { + delay:function ($q, $rootScope) { + defer = $q.defer(); + if (!html) { + var dependencies = [controllerName, "text!" + templateUrl]; + if (directives) { + dependencies = dependencies.concat(directives); + } + require(dependencies, function () { + var controller = arguments[0], + template = arguments[1]; + + for (var i = 2; i < arguments.length; i++) { + lazyDirectives.register(arguments[i]); + } + + $controllerProvider.register(controllerName, controller); + html = template; + defer.resolve(); + $rootScope.$apply() + }) + + } else { + defer.resolve(); + } + return defer.promise; + } + } + + return routeDefinition; + } + + return { + setControllerProvider:setControllerProvider, + setCompileProvider:setCompileProvider, + config:config + } +}) + diff --git a/app/partials/view2.html b/app/partials/view2.html index 92257b3..4ab87da 100644 --- a/app/partials/view2.html +++ b/app/partials/view2.html @@ -1,3 +1,4 @@

    {{message}}

    +
    Version directive: