<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Section Archives - Blog IT</title>
	<atom:link href="https://blogit.create.pt/tag/section/feed/" rel="self" type="application/rss+xml" />
	<link>https://blogit.create.pt/tag/section/</link>
	<description>Create IT blogger community</description>
	<lastBuildDate>Thu, 10 Jan 2019 12:46:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.1</generator>
	<item>
		<title>Automatic generation of Umbraco packages with Grunt</title>
		<link>https://blogit.create.pt/andresantos/2016/03/07/automatic-generation-of-umbraco-packages-with-grunt/</link>
					<comments>https://blogit.create.pt/andresantos/2016/03/07/automatic-generation-of-umbraco-packages-with-grunt/#comments</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Mon, 07 Mar 2016 16:03:50 +0000</pubDate>
				<category><![CDATA[Umbraco]]></category>
		<category><![CDATA[automatization]]></category>
		<category><![CDATA[Backoffice extension]]></category>
		<category><![CDATA[grunt]]></category>
		<category><![CDATA[npm]]></category>
		<category><![CDATA[NPM Scripts Task Runner]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[Section]]></category>
		<category><![CDATA[visual studio]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=1161</guid>

					<description><![CDATA[<p>Manually creating Umbraco packages can be tiresome. If you&#8217;re continuously building upon the same package, doing it manually is wasting time that can be more useful developing new features. This problem presented itself to me when improving Approve It. In order to create the Umbraco package I need several things: The main assembly The new dashboard [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2016/03/07/automatic-generation-of-umbraco-packages-with-grunt/">Automatic generation of Umbraco packages with Grunt</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Manually creating Umbraco packages can be tiresome.</p>
<p>If you&#8217;re continuously building upon the same package, doing it manually is wasting time that can be more useful developing new features.</p>
<p>This problem presented itself to me when improving <a href="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" target="_blank" rel="noopener">Approve It</a>. In order to create the Umbraco package I need several things:</p>
<ul>
<li>The main assembly</li>
<li>The new dashboard section html file</li>
<li>The App_Plugins folder which contains every angular controller and views, javascript frameworks and custom css</li>
<li>The <a href="http://packageactioncontrib.codeplex.com/" target="_blank" rel="noopener">Package Actions Contrib</a> assembly and its respective actions that enable me to bundle some translations in the package</li>
</ul>
<p>I decided to go with <a href="http://gruntjs.com/getting-started" target="_blank" rel="noopener">Grunt</a> and the <a href="https://www.npmjs.com/package/grunt-umbraco-package" target="_blank" rel="noopener">Grunt Umbraco Package</a> task. A grunt file is a script that typically automates the process of executing some tasks. These scripts can be executed on top of <a href="https://www.npmjs.com/" target="_blank" rel="noopener">NPM</a>, a package manager for javscript that provides a command line tool to run its packages. To streamline even more the package creation, I installed a Visual Studio extension called <a href="https://visualstudiogallery.msdn.microsoft.com/8f2f2cbc-4da5-43ba-9de2-c9d08ade4941" target="_blank" rel="noopener">NPM Scripts Task Runner</a>, that detects the grunt file and provides a simples UI to handle its tasks.</p>
<p><span id="more-6479"></span></p>
<h3>Step 1 &#8211; Install NPM</h3>
<p>With NPM installed we are able to execute a Grunt file.</p>
<h3>Step 2 &#8211; Install NPM Scripts Task Runner</h3>
<p>The Visual Studio extension:</p>
<figure id="attachment_1241" aria-describedby="caption-attachment-1241" style="width: 471px" class="wp-caption alignnone"><a href="http://blogit-create.com/wp-content/uploads/2016/03/npmscriptsvs.png" rel="attachment wp-att-1241"><img fetchpriority="high" decoding="async" class="wp-image-1241 size-full" src="http://blogit-create.com/wp-content/uploads/2016/03/npmscriptsvs.png" alt="NPM Scripts Task Runner Visual Studio extension" width="471" height="235" /></a><figcaption id="caption-attachment-1241" class="wp-caption-text">NPM Scripts Task Runner Visual Studio extension</figcaption></figure>
<h3>Step 3 &#8211; Create a Grunt file</h3>
<p>And place it in your project:</p>
<pre class="brush: jscript; title: Gruntfile.js; notranslate">
module.exports = function (grunt) {

    // Setup
    var pkg = grunt.file.readJSON('package.json');
    var projectRoot = 'C:/path/to/project/ApproveIt/';
    var packageNamespace = &quot;Create.Plugin&quot;;

    // Grunt Configuration
    grunt.initConfig({
        pkg: pkg,
        clean: {
            files: &#x5B;
                'bld/App_Plugins',
                'bld/bin',
                'bld/Umbraco'
            ]
        },
        copy: {
            release: {
                files: &#x5B;
                    {
                        expand: true,
                        cwd: projectRoot + 'bin/',
                        src: &#x5B;
                            packageNamespace + '.' + pkg.name + '.dll',
                            'PackageActionsContrib.dll'
                        ],
                        dest: 'bld/bin/'
                    },
                    {
                        expand: true,
                        cwd: projectRoot + 'App_Plugins/',
                        src: &#x5B;'**'],
                        dest: 'bld/App_Plugins/'
                    },
                    {
                        expand: true,
                        cwd: projectRoot + 'Dashboard/Views/dashboard/approveIt/',
                        src: &#x5B;'approveItdashboardintro.html'],
                        dest: &quot;bld/Umbraco/Views/dashboard/approveIt/&quot;
                    }
                ]
            }
        },
        umbracoPackage: {
            release: {
                src: 'bld/',
                dest: 'bin/umbraco',
                options: {
                    name: pkg.name,
                    version: pkg.version,
                    url: pkg.url,
                    license: pkg.license.name,
                    licenseUrl: pkg.license.url,
                    author: pkg.author.name,
                    authorUrl: pkg.author.url,
                    readme: pkg.readme,
                    outputName: pkg.name + '.v' + pkg.version + '.zip',
                    manifest: 'package.xml'
                }
            }
        }
    });

    // Loading of Grunt Tasks
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-umbraco-package');
};
</pre>
<p>This file has three sections, which I&#8217;ll explain in a different order:</p>
<ol>
<li>Setup</li>
<li>Grunt configuration</li>
<li>Loading of grunt tasks</li>
</ol>
<h4>Loading of Grunt Tasks</h4>
<p>Most actions we need a grunt file to execute are simplified by the use of existing Grunt tasks. In my case, I only need 3:</p>
<ol>
<li><em>grunt-contrib-clean</em>: deletes files and folders</li>
<li><em>grunt-contrib-copy</em>: copies files and folders</li>
<li><em>grunt-umbraco-package</em>: generates an umbraco package</li>
</ol>
<h4>Grunt File Setup</h4>
<p>Here I define a set of variables and load an external configuration file that contains project properties I use later on:</p>
<pre class="brush: jscript; title: package.json; notranslate">
{
  &quot;author&quot;: {
    &quot;name&quot;: &quot;André Santos&quot;,
    &quot;url&quot;: &quot;http://www.create.pt&quot;
  },
  &quot;devDependencies&quot;: {
    &quot;grunt&quot;: &quot;~0.4.5&quot;,
    &quot;grunt-contrib-clean&quot;: &quot;^0.6.0&quot;,
    &quot;grunt-contrib-copy&quot;: &quot;~0.4.1&quot;,
    &quot;grunt-umbraco-package&quot;: &quot;1.0.0&quot;
  },
  &quot;license&quot;: {
    &quot;name&quot;: &quot;MIT&quot;,
    &quot;url&quot;: &quot;http://opensource.org/licenses/MIT&quot;
  },
  &quot;name&quot;: &quot;ApproveIt&quot;,
  &quot;readme&quot;: &quot;Umbraco Plugin that creates a section that shows all the content that is waiting approval for publishing.&quot;,
  &quot;url&quot;: &quot;https://our.umbraco.org/projects/backoffice-extensions/approve-it/&quot;,
  &quot;version&quot;: &quot;1.0.1&quot;
}
</pre>
<h4>Grunt Configuration</h4>
<p>This section is where everything comes together. The <em>package.json</em> configuration file is loaded and the three aforementioned grunt tasks are implemented:</p>
<h5>Clean</h5>
<p>In here, the directories used as the source for the umbraco package creation, are configured so that when we can empty them at will</p>
<h5>Copy</h5>
<p>This task copies every file needed by the plugin to a centralized location, creating a snapshot of our plugin. We copy full directories and hand picked files as needed.</p>
<h5>Umbraco Package</h5>
<p>Finally, this task picks up every file we have copied and creates the final Umbraco package. It uses the configuration properties set in <em>package.json</em> and uses a custom <em>package.xml</em> file so that I can include my custom post umbraco package install actions (using Package Actions Contrib):</p>
<pre class="brush: xml; title: package.xml; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;
&lt;umbPackage&gt;
  &lt;info&gt;
    &lt;package&gt;
      &lt;name&gt;&lt;%= name %&gt;&lt;/name&gt;
      &lt;version&gt;&lt;%= version %&gt;&lt;/version&gt;
      &lt;license url=&quot;&lt;%= licenseUrl %&gt;&quot;&gt;&lt;%= license %&gt;&lt;/license&gt;
      &lt;url&gt;&lt;%= url %&gt;&lt;/url&gt;
      &lt;requirements&gt;
        &lt;major&gt;3&lt;/major&gt;
        &lt;minor&gt;0&lt;/minor&gt;
        &lt;patch&gt;0&lt;/patch&gt;
      &lt;/requirements&gt;
    &lt;/package&gt;
    &lt;author&gt;
      &lt;name&gt;&lt;%= author %&gt;&lt;/name&gt;
      &lt;website&gt;&lt;%= authorUrl %&gt;&lt;/website&gt;
    &lt;/author&gt;
    &lt;readme&gt;&lt;!&#x5B;CDATA&#x5B;&lt;%= readme %&gt;]]&gt;&lt;/readme&gt;
  &lt;/info&gt;
  &lt;DocumentTypes /&gt;
  &lt;Templates /&gt;
  &lt;Stylesheets /&gt;
  &lt;Macros /&gt;
  &lt;DictionaryItems /&gt;
  &lt;Languages /&gt;
  &lt;DataTypes /&gt;
  &lt;control /&gt;
  &lt;Actions&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;addDashboardSection&quot; dashboardAlias=&quot;StartupApproveItDashboardSection&quot;&gt;
      &lt;section&gt;
        &lt;areas&gt;
          &lt;area&gt;approveIt&lt;/area&gt;
        &lt;/areas&gt;
        &lt;tab caption=&quot;Get Started&quot;&gt;
          &lt;control showOnce=&quot;true&quot; addPanel=&quot;true&quot; panelCaption=&quot;&quot;&gt;
            views/dashboard/approveIt/approveItdashboardintro.html
          &lt;/control&gt;
        &lt;/tab&gt;
      &lt;/section&gt;
    &lt;/Action&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;en&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;pt&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;cs&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;da&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;en_us&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;es&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;fr&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;he&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;it&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ja&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ko&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;nl&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;no&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;pl&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ru&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;sv&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;zh&quot; position=&quot;end&quot; area=&quot;sections&quot; key=&quot;approveIt&quot; value=&quot;Approve It&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;en&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;pt&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Editador por&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;cs&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;da&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;en_us&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;es&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;fr&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;he&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;it&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ja&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ko&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;nl&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;no&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;pl&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;ru&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;sv&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
    &lt;Action runat=&quot;install&quot; undo=&quot;true&quot; alias=&quot;AddLanguageFileKey&quot; language=&quot;zh&quot; position=&quot;end&quot; area=&quot;general&quot; key=&quot;approveitupdatedBy&quot; value=&quot;Updated by&quot; /&gt;
  &lt;/Actions&gt;
  &lt;files&gt;
  	&lt;% files.forEach(function(file) { %&gt;
  	&lt;file&gt;
      &lt;guid&gt;&lt;%= file.guid %&gt;&lt;/guid&gt;
      &lt;orgPath&gt;&lt;%= file.dir %&gt;&lt;/orgPath&gt;
      &lt;orgName&gt;&lt;%= file.name %&gt;&lt;/orgName&gt;
    &lt;/file&gt;
	&lt;% }); %&gt;
  &lt;/files&gt;
&lt;/umbPackage&gt;
</pre>
<p>This file uses the Grunt templating engine so that, not only can I include the Package Action Contrib custom actions, but also some custom variables, such as:</p>
<ul>
<li>The mandatory list of files that is automatically updated when a new file is added to the project output</li>
<li>The <em>package.json</em> variables</li>
</ul>
<p>That&#8217;s it! We can now create new versions of Approve It without having to go into the Umbraco backoffice and doing it manually every time we need a new package version.</p>
<p><em>You can find the complete source code in my GitHub: <a href="https://github.com/ViGiLnT/ApproveIt" target="_blank" rel="noopener">https://github.com/ViGiLnT/ApproveIt</a>. You can download the Approve It package here: <a href="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" target="_blank" rel="noopener">https://our.umbraco.org/projects/backoffice-extensions/approve-it/</a>.</em></p>
<p>The post <a href="https://blogit.create.pt/andresantos/2016/03/07/automatic-generation-of-umbraco-packages-with-grunt/">Automatic generation of Umbraco packages with Grunt</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2016/03/07/automatic-generation-of-umbraco-packages-with-grunt/feed/</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
			</item>
		<item>
		<title>Building an Umbraco 7 backoffice extension – Part III</title>
		<link>https://blogit.create.pt/andresantos/2015/11/30/building-an-umbraco-7-backoffice-extension-part-iii/</link>
					<comments>https://blogit.create.pt/andresantos/2015/11/30/building-an-umbraco-7-backoffice-extension-part-iii/#comments</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Mon, 30 Nov 2015 15:02:06 +0000</pubDate>
				<category><![CDATA[Umbraco]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[Backoffice extension]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[Section]]></category>
		<category><![CDATA[WebMatrix]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=841</guid>

					<description><![CDATA[<p>The previous post (Part II) showed how to populate the content tree of a custom Umbraco backoffice section. This one presents a way for content managers to quickly handle each post pending approval, which means we&#8217;re going to create our own AngularJS controller and view. AngularJS is a MVC javascript framework mainly mantained by Google which [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/11/30/building-an-umbraco-7-backoffice-extension-part-iii/">Building an Umbraco 7 backoffice extension – Part III</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span class="dropcap dropcap3">T</span>he previous post (<a title="Building an Umbraco 7 backoffice extension - Part II" href="http://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii" target="_blank" rel="noopener">Part II</a>) showed how to populate the content tree of a custom Umbraco backoffice section. This one presents a way for content managers to quickly handle each post pending approval, which means we&#8217;re going to create our own AngularJS controller and view.</p>
<p><a title="Angular.JS" href="https://angularjs.org/" target="_blank" rel="noopener">AngularJS</a> is a MVC javascript framework mainly mantained by Google which primary goal is to aid in the development of single-page applications. It&#8217;s use on the Umbraco backoffice was the most notable change when Umbraco 7 was first released.</p>
<p>When the content manager selects one node pending approval we want him to be able to take three quick actions:</p>
<ul>
<li>get some information about that node;</li>
<li>quickly access it in the content section;</li>
<li>quickly publish it.</li>
</ul>
<p><span id="more-6478"></span></p>
<p>New Angular controllers and views must be placed in a specific Umbraco directory, following a specific directory structure:</p>
<ul>
<li>the main directory must reside at ~\App_Plugins\ApproveIt &#8211; the plugin name</li>
<li>the views and controllers must reside at App_Plugins\ApproveIt\backoffice\approvalTree\ &#8211; the tree controller name</li>
</ul>
<p>First things first:</p>
<p>Create a package manifest so that Umbraco knows there are new javascript files available, and place it in the root of App_Plugins\ApproveIt directory.</p>
<pre class="brush: plain; title: package.manifest; notranslate">

{
	javascript: &#x5B;
		'~/App_Plugins/ApproveIt/backoffice/approvalTree/edit.controller.js',
		'~/App_Plugins/ApproveIt/approval.resource.js'
	]
}

</pre>
<p>Then we must create the javascript files referenced by the manifest and the respective angular view.</p>
<pre class="brush: jscript; title: approval.resource.js; notranslate">

angular.module(&quot;umbraco.resources&quot;)
	.factory(&quot;approvalResource&quot;, function ($http) {
	    return {
	        getById: function (id) {
	            return $http.get(&quot;backoffice/ApproveIt/ApprovalApi/GetById?id=&quot; + id);
	        },
	        publish: function (id) {
	            return $http.post(&quot;backoffice/ApproveIt/ApprovalApi/PostPublish?id=&quot; + id);
	        }
	    };
	});
</pre>
<p>This javascript file provides a new <a title="Angular Service" href="https://docs.angularjs.org/guide/services">Angular Service</a> that can then be used by Angular controllers. This service is no more than a facade for the ApprovalApiController created on <a title="Building an Umbraco 7 backoffice extension - Part II" href="http://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii" target="_blank" rel="noopener">Part II</a>. The methods it connects to are created further on.</p>
<pre class="brush: jscript; title: edit.controller.js; notranslate">

angular.module(&quot;umbraco&quot;).controller(&quot;Approval.ApprovalEditController&quot;,
	function ($scope, $routeParams, approvalResource, notificationsService, navigationService) {

	    $scope.loaded = false;

	    if ($routeParams.id == -1) {
	        $scope.node = {};
	        $scope.loaded = true;
	    }
	    else {
	        approvalResource.getById($routeParams.id).then(function (response) {
	            $scope.node = response.data;
	            $scope.loaded = true;
	        });
	    }

	    $scope.publish = function (node) {
	        approvalResource.publish(node.Id).then(function (response) {
	            $scope.node = response.data;
	            $scope.contentForm.$dirty = false;
	            navigationService.syncTree({ tree: 'approvalTree', path: &#x5B;-1, -1], forceReload: true });
	            notificationsService.success(&quot;Success&quot;, node.Name + &quot; has been published&quot;);
	        });
	    };

	});

</pre>
<p>This Angular controller is called when the Approve It section is being used:</p>
<ul>
<li>If no node is selected (for instance, when we access this section for the first time) we do nothing;</li>
<li>If a node is selected (<em>$routeParams.id != -1</em>) we request the node details through our approval.resource service facade</li>
<li>Finally, the quick publish method is also implemented here. This methods calls the ApprovalResource service which then invokes the publish method of the ApprovalApiController.</li>
</ul>
<pre class="brush: xml; title: edit.html; notranslate">

&lt;form name=&quot;contentForm&quot;
      ng-controller=&quot;Approval.ApprovalEditController&quot;
      ng-show=&quot;loaded&quot;
      ng-submit=&quot;publish(node)&quot;
      val-form-manager&gt;
    &lt;umb-panel&gt;
        &lt;umb-header&gt;
            &lt;div class=&quot;span7&quot;&gt;
                &lt;umb-content-name placeholder=&quot;@placeholders_entername&quot;
                                  ng-model=&quot;node.Name&quot; /&gt;
            &lt;/div&gt;
            &lt;div class=&quot;span5&quot;&gt;
                &lt;div class=&quot;btn-toolbar pull-right umb-btn-toolbar&quot;&gt;
                    &lt;umb-options-menu ng-show=&quot;currentNode&quot;
                                      current-node=&quot;currentNode&quot;
                                      current-section=&quot;{{currentSection}}&quot;&gt;
                    &lt;/umb-options-menu&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/umb-header&gt;
        &lt;div class=&quot;umb-panel-body umb-scrollable row-fluid&quot;&gt;
            &lt;div class=&quot;tab-content form-horizontal&quot; style=&quot;padding-bottom: 90px&quot;&gt;
                &lt;div class=&quot;umb-pane&quot;&gt;

                    &lt;umb-control-group label=&quot;Name&quot; description=&quot;Content's name&quot;&gt;
                        &lt;input type=&quot;text&quot; class=&quot;umb-editor umb-textstring&quot; ng-model=&quot;node.Name&quot; required /&gt;
                    &lt;/umb-control-group&gt;

                    &lt;div class=&quot;umb-tab-buttons&quot; detect-fold&gt;
                        &lt;div class=&quot;btn-group&quot;&gt;
                            &lt;a class=&quot;btn&quot; ng-href=&quot;#/content/content/edit/{{node.Id}}&quot;&gt;
                                Show
                            &lt;/a&gt;
                        &lt;/div&gt;
                        &lt;div class=&quot;btn-group&quot;&gt;
                            &lt;button type=&quot;submit&quot; data-hotkey=&quot;ctrl+s&quot; class=&quot;btn btn-success&quot;&gt;
                                Publish
                            &lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                &lt;/div&gt;
            &lt;/div&gt;
        &lt;/div&gt;
    &lt;/umb-panel&gt;
&lt;/form&gt;
</pre>
<p>The node view presents the waiting approval page name and two buttons: one to quickly navigate to it&#8217;s details and another to publish it.</p>
<p>Finally, we need to update the ApprovalApiController.cs to include two new methods:</p>
<pre class="brush: csharp; title: ; notranslate">

public IContent GetById(int id)
{
    IContent content = ApplicationContext.Services.ContentService.GetById(id);
    return content;
}

public IContent PostPublish(int id)
{
    IContent node = ApplicationContext.Services.ContentService.GetById(id);
    ApplicationContext.Services.ContentService.Publish(node);

    return node;
}
</pre>
<ul>
<li>GetById: returns the node details to the angular view</li>
<li>PostPublish: publishes the node being viewed</li>
</ul>
<p>By following these steps we are able to create a complete new Umbraco backoffice section that provides us with a way to manage every site content waiting approval for publishing:</p>
<p><a href="http://blogit-create.com/wp-content/uploads/2015/11/approveit1.0.png"><img decoding="async" class="aligncenter wp-image-1031" src="http://blogit-create.com/wp-content/uploads/2015/11/approveit1.0.png" alt="approveit1.0" width="600" height="410" /></a></p>
<p><em>If you want to see how this plugin as been evolving, you can check its source code in github: <a title="https://github.com/ViGiLnT/ApproveIt" href="https://github.com/ViGiLnT/ApproveIt" target="_blank" rel="noopener">https://github.com/ViGiLnT/ApproveIt</a>. You can also download the plugin ready to be installed at Umbraco&#8217;s extensions repository: <a title="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" href="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" target="_blank" rel="noopener">https://our.umbraco.org/projects/backoffice-extensions/approve-it/</a>. Other Umbraco 7 tutorials and information can be found here: <a title="http://umbraco.github.io/Belle" href="http://umbraco.github.io/Belle" target="_blank" rel="noopener">http://umbraco.github.io/Belle</a>.</em></p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/11/30/building-an-umbraco-7-backoffice-extension-part-iii/">Building an Umbraco 7 backoffice extension – Part III</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2015/11/30/building-an-umbraco-7-backoffice-extension-part-iii/feed/</wfw:commentRss>
			<slash:comments>12</slash:comments>
		
		
			</item>
		<item>
		<title>Building an Umbraco 7 backoffice extension – Part II</title>
		<link>https://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii/</link>
					<comments>https://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii/#respond</comments>
		
		<dc:creator><![CDATA[André Santos]]></dc:creator>
		<pubDate>Mon, 23 Nov 2015 10:00:56 +0000</pubDate>
				<category><![CDATA[Umbraco]]></category>
		<category><![CDATA[.NET]]></category>
		<category><![CDATA[AngularJS]]></category>
		<category><![CDATA[Backoffice extension]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[mvc]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[Plugin]]></category>
		<category><![CDATA[Section]]></category>
		<category><![CDATA[WebMatrix]]></category>
		<guid isPermaLink="false">http://blogit.create.pt/andresantos/?p=721</guid>

					<description><![CDATA[<p>The previous post (Building an Umbraco 7 backoffice extension – Part I), demonstrated how easy it is to create a new section in Umbraco&#8217;s backoffice. This post will show how we can populate this new section with meaningful content coming directly from the backoffice. To begin with, we must reference a few more assemblies (also [&#8230;]</p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii/">Building an Umbraco 7 backoffice extension – Part II</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><span class="dropcap dropcap3">T</span>he previous post (<a title="Building an Umbraco 7 backoffice extension – Part I" href="http://blogit.create.pt/andresantos/2015/11/16/building-an-umbraco-7-backoffice-extension-part-i/" target="_blank" rel="noopener">Building an Umbraco 7 backoffice extension – Part I</a>), demonstrated how easy it is to create a new section in Umbraco&#8217;s backoffice. This post will show how we can populate this new section with meaningful content coming directly from the backoffice.</p>
<p>To begin with, we must reference a few more assemblies (also available at the Umbraco&#8217;s installation <em>bin</em> directory):</p>
<ul>
<li>umbraco.dll</li>
<li>cms.dll</li>
<li>Umbraco.Core.dll</li>
<li>System.Web.Http</li>
<li>System.Net.Http.Formatting</li>
</ul>
<p>Then we can populate our section with a tree containing content awaiting approval. To accomplish this we must extend an Umbraco class named TreeController and decorate it with information about our <strong>Approve It</strong> plugin:</p>
<p><span id="more-6471"></span></p>
<pre class="brush: csharp; title: ; notranslate">

&#x5B;Tree(&quot;approveIt&quot;, &quot;approvalTree&quot;, &quot;Content for Approval&quot;)]
&#x5B;PluginController(&quot;ApproveIt&quot;)]
public class ApprovalTreeController : TreeController
{
   protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings)
   {
       var ctrl = new ApprovalApiController();
       var nodes = new TreeNodeCollection();

       IUser user = UmbracoContext.Security.CurrentUser;

       //check if we're rendering the root node's children
       if (id == Constants.System.Root.ToInvariantString())
       {
           foreach (IContent content in ctrl.GetAll(user))
           {
                var node = CreateTreeNode(
                    content.Id.ToString(),
                    &quot;-1&quot;,
                    queryStrings,
                    content.Name,
                    &quot;icon-document&quot;,
                    false);

               nodes.Add(node);
            }
       }

        return nodes;
    }

    protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
    {
        var menu = new MenuItemCollection();

        if (id == Constants.System.Root.ToInvariantString())
        {
            // root actions
            menu.Items.Add&lt;RefreshNode, ActionRefresh&gt;(
                ApplicationContext.Services.TextService.Localize(ActionRefresh.Instance.Alias));
        }

        return menu;
    }
}
</pre>
<p>To create a tree we must implement two methods:</p>
<ol>
<li>GetTreeNodes: in here we call the GetAll method of the ApprovalApiController that we&#8217;ll create in the following. This GetAll method returns a list of content waiting approval and we just iterate through it all and create tree nodes;</li>
<li>GetMenuForNode: presents a dropdown menu when we right click the root node to refresh the list.</li>
</ol>
<p>Next we create our custom WebAPI and name it ApprovalApiController. For it to be available in our site, we need only extend the UmbracoAuthorizedJsonController.</p>
<pre class="brush: csharp; title: ; notranslate">

&#x5B;PluginController(&quot;ApproveIt&quot;)]
public class ApprovalApiController : UmbracoAuthorizedJsonController
{
    public IList&lt;IContent&gt; UnpublishedContent { get; set; }

    public IEnumerable&lt;IContent&gt; GetAll(IUser user)
    {
        UnpublishedContent = new List&lt;IContent&gt;();

        IList&lt;IContent&gt; root = ApplicationContext.Services.ContentService.GetRootContent().ToList();

        foreach (IContent content in root)
        {
            GetNode(content);
        }

        return UnpublishedContent;
    }

    private void GetNode(IContent node)
    {
        if (!node.Published)
        {
            UnpublishedContent.Add(node);
        }

        foreach (IContent child in ApplicationContext.Services.ContentService.GetChildren(node.Id))
        {
            GetNode(child);
        }
    }
}

</pre>
<p>The GetAll method, iterates through all the nodes in the content section and finds the ones that are not published, that is, that are waiting approval.</p>
<p>With these two classes we are able to populate our section with a tree containing the content nodes that are waiting approval:</p>
<p><a href="http://blogit-create.com/wp-content/uploads/2015/11/approveit2.png"><img decoding="async" class="alignnone size-medium wp-image-791" src="http://blogit-create.com/wp-content/uploads/2015/11/approveit2-167x300.png" alt="approveit2" width="167" height="300" /></a></p>
<p>The next post in the series will show how to create the Angular view and controller that will enable content managers to actually manage the content waiting approval.</p>
<p><em>The Approve It extension can be found here: <a title="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" href="https://our.umbraco.org/projects/backoffice-extensions/approve-it/" target="_blank" rel="noopener">https://our.umbraco.org/projects/backoffice-extensions/approve-it/</a>. The complete source code can be found here: <a title="https://github.com/ViGiLnT/ApproveIt" href="https://github.com/ViGiLnT/ApproveIt" target="_blank" rel="noopener">https://github.com/ViGiLnT/ApproveIt</a>.</em></p>
<p>The post <a href="https://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii/">Building an Umbraco 7 backoffice extension – Part II</a> appeared first on <a href="https://blogit.create.pt">Blog IT</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blogit.create.pt/andresantos/2015/11/23/building-an-umbraco-7-backoffice-extension-part-ii/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
