Example #1
0
        /// <summary>
        /// Occurs when the content was just reloaded. This occurs lazily
        /// when <see cref="Content"/> property is touched.
        /// </summary>
        protected override void OnContentChange()
        {
            // Call the base
            base.OnContentChange();

            // Each view is dependant on the code-behind script, with the same name
            this.Dependancies.Clear();

            // Soft requirement, components don't really need to have a code-behind
            // as it might be purely visual components.
            if(this.CodeBehind != null)
                this.Dependancies.AddCodeBehind(this.CodeBehind);

            // Read the stream and write a string
            using (var stream = new MemoryStream(this.Content))
            using (var reader = new StreamReader(stream))
            using (var body = new StringWriter())
            {
                // Read line by line and render the body which is not dependancy
                string line;
                while ((line = reader.ReadLine()) != null)
                {
                    if (!this.Dependancies.TryAddParsed(line))
                        body.WriteLine(line);
                }

                // Create a final text version
                this.Text = body.ToString();

                // Minify HTML
                this.Text = Regex.Replace(this.Text, @"\n|\t", " ");
                this.Text = Regex.Replace(this.Text, @">\s+<", "><").Trim();
            }

            // Create a writer for javascript
            using(var writer = new MetaScriptWriter())
            {
                writer.WriteLine("app.lazy.directive('{0}', ['$parse', function($parse)", this.Name.AsDirectiveName());
                writer.WriteLine("{");
                writer.WriteLine(   "return {");
                writer.WriteLine(       "restrict: 'E',");
                writer.WriteLine(       "transclude: true,");

                // If we have a code behind for the element, we need to set up the
                // controller and a linking function.
                if (this.CodeBehind != null)
                {
                    // Get the type name of the surrogate controller
                    var type = this.CodeBehind.Surrogate.Type;

                    // Set the controller
                    writer.WriteLine("controller: ['$scope', '$server', '$parse', {0}Ctrl],", type);

                    // Linking function that executes the handhshake for each element
                    writer.WriteLine("link: function(scope, element, attrs)");
                    writer.WriteLine("{");

                    //writer.WriteLine("scope.$apply(function(){");
                    foreach (var property in this.CodeBehind.Surrogate.Properties)
                    {
                        // We only handle settable properties
                        if (!property.HasSetter)
                            continue;

                        writer.WriteLine("scope.{0} = $parse(attrs['{0}'])(scope.$parent);", property.Name);

                    }
                    //writer.WriteLine("});");

                    //writer.WriteLine("console.debug(scope);");
                    //writer.WriteLine("console.debug(attrs);");
                    //writer.WriteLine("console.log('handshake: " + type + " for parent ' + scope.$parent.$i);");
                    writer.WriteLine("},");

                }

                // Create a completely isolate scope without any bindings
                writer.WriteLine("scope: {},");

                writer.WriteLine(       "templateUrl: 'element/{0}',", this.Key);
                writer.WriteLine(       "replace: true");
                writer.WriteLine(   "};");
                writer.WriteLine("}]);");

                this.Code = writer.ToString();
            }
        }
Example #2
0
        /// <summary>
        /// Compiles several proxies and returns a javascript string.
        /// </summary>
        /// <param name="proxies">The proxies to compile in a single file.</param>
        /// <param name="type">The type of the surrogate to compile.</param>
        /// <returns>The compiled output.</returns>
        public static string Compile(SurrogateType type, Surrogate proxy)
        {
            using (var writer = new MetaScriptWriter())
            {

                //writer.WriteLine("app.controllerProvider.register('{0}', function ($scope, $server)", proxy.Type);
                writer.WriteLine("function {0}Ctrl ($scope, $server, $parse)", proxy.Type);
                writer.WriteLine("{");

                // For each property:
                foreach (var prop in proxy.Properties.Where(p => p.Modifier == SurrogateMemberModifier.Public))
                {
                    // A function that attaches a property value to the scope
                    writer.WriteLine("var attach_{0} = function(value)", prop.Name, proxy.Type, proxy.Name);
                    writer.WriteLine("{");
                    writer.WriteLine(   "$scope.{0} = value;", prop.Name);
                    writer.WriteLine("};");

                    // If we have a getter, add the querying part
                    if (prop.HasGetter)
                    {
                        // Make the getter
                        writer.WriteLine("$scope.get{0} = function()", prop.Name.UppercaseFirst());
                        writer.WriteLine("{");
                        writer.WriteLine(   "$server.query($scope.$i, '{0}', null, attach_{0});", prop.Name);
                        writer.WriteLine("};");
                    }

                    // If we have a setter, allow the setter to notify the server
                    if (prop.HasSetter)
                    {

                        // Make the getter and setter
                        writer.WriteLine("$scope.set{0} = function()", prop.Name.UppercaseFirst());
                        writer.WriteLine("{");
                        //writer.WriteLine("$server.onPropertySet($scope.$i, '{0}', null, attach_{0});", prop.Name);
                        writer.WriteLine("};");
                    }

                    // Insert an empty property
                    writer.WriteLine("$scope.{0} = null;", prop.Name);
                    writer.WriteLine();

                }

                // For each function:
                foreach (var func in proxy.Methods.Where(p => p.Modifier == SurrogateMemberModifier.Public))
                {
                    writer.Write("var set_{0} = function(o)", func.Name, proxy.Type, proxy.Name);
                    writer.WriteLine("{");
                    writer.WriteLine("$scope.result.{0} = o;", func.Name);
                    writer.WriteLine("};");

                    // Make the function
                    writer.Write("$scope.{0} = function()", func.Name);
                    writer.WriteLine("{");
                    writer.WriteLine("$server.query($scope.$i, '{0}', $server.makeArgs(arguments), set_{0});", func.Name);
                    writer.WriteLine("};");
                }

                // Gets the handhsake and populates the oid scope
                writer.WriteLine("$scope.$$w = angular.watchObject;");

                writer.WriteLine("var onConstruct = function(oid){");
                writer.WriteLine("$scope.$i = oid;");
                writer.WriteLine("$scope.result = new Object();");
                foreach (var prop in proxy.Properties.Where(p => p.Modifier == SurrogateMemberModifier.Public))
                {
                    // For a code-behind of a view only:
                    if (type == SurrogateType.ViewSurrogate)
                    {
                        // Call the getter once
                        if (prop.HasGetter)
                            writer.WriteLine("$scope.get{0}();", prop.Name.UppercaseFirst());
                    }

                    // If there's a public setter, attach angular.watchObject
                    if (prop.HasSetter)
                    {
                        // In any case, we need to be able to watch the property change and propagate it to
                        // the server.
                        writer.WriteLine("$scope.$$w($server, $parse, '{0}', $server.onPropertySet);", prop.Name);

                        // The element should propagate all properties set originally via its
                        // attributes back to the server, as they might have been bound to some
                        // UI elements and values.
                        if (type == SurrogateType.ElementSurrogate)
                        {
                            // set the new value arguments
                            writer.WriteLine("var propertyValue = new Object();");
                            writer.WriteLine("propertyValue.target = oid;");
                            writer.WriteLine("propertyValue.name = '{0}';", prop.Name);
                            writer.WriteLine("propertyValue.value = $scope['{0}'];", prop.Name);

                            // Notify the server
                            writer.WriteLine("$server.onPropertySet(propertyValue);");

                        }
                    }
                }
                writer.WriteLine("};");

                // Add a property to the scope with the name
                writer.WriteLine("$scope.$type = '{0}';", proxy.Type);

                // Call the view constructor
                if (type == SurrogateType.ViewSurrogate)
                    writer.WriteLine("$server.view('{0}', onConstruct);", proxy.Type);

                // Call the element constructor
                if (type == SurrogateType.ElementSurrogate)
                    writer.WriteLine("$server.element('{0}', $scope.$parent.$type, onConstruct);", proxy.Type);

                // Handles the property change event
                writer.WriteLine("$scope.$on('e:property', function (e, args) {");
                writer.WriteLine("if(typeof($scope.$i) === 'undefined'){return;}");
                writer.WriteLine("if($scope.$i == args.target && $scope.hasOwnProperty(args.name))");
                writer.WriteLine(   "$scope[args.name] = $server.deserialize(args.value);");
                writer.WriteLine("});");

                writer.WriteLine("};");
                writer.WriteLine();

                writer.WriteLine("{0}Ctrl.$inject = ['$scope', '$server', '$parse'];", proxy.Type);

                // Register as a controller
                writer.WriteLine("app.lazy.controller('{0}', {0}Ctrl);", proxy.Type);

                return writer.ToString();
            }
        }