README.md 7.78 KB
Newer Older
Antony's avatar
Antony committed
1
# UmbracoContactNumber
2
Editor with stored value:
Antony's avatar
Antony committed
3

4
![Read-only mode (default).](images/property-editor-read.png "Read-only mode (default).")
5

6
When *Edit* is clicked, the view expands:
7

8
9
10
11
12
13
14
15
16
17
18
19
20
![Editor with valid phone number length for selected country code.](images/property-editor-edit-dk-success.png "Editor with valid phone number length for selected country code.")

When clicking the country, a dropdown is shown:

![Country dropdown expanded.](images/property-editor-edit-dk-success-dropdown.png "Country dropdown expanded.")

If the number does not have one of the known correct lengths for the country, or if no number lengths are known for the country, the green checkbox is not shown:

![Turkish phone number. Validity of phone number length is unknown.](images/property-editor-edit-tr.png "Turkish phone number. Validity of phone number length is unknown.")

# Build steps

## How to build the NuGet package
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
This is automated by properties in the .csproj file by setting the following property to true:

```xml
<Project ...>
	<PropertyGroup>
		...
		<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
		...
	</PropertyGroup>
	...
</Project>
```

Furthermore, to fill out the NuGet package information such as owner, name, and so on, the following properties are set:

```xml
<Project ...>
	<PropertyGroup>
		<Id>Appstract.UmbracoContactNumber</Id>
		<Authors>Appstract Consulting Aps</Authors>
		<Owners>Appstract Consulting Aps</Owners>
		<PackageProjectUrl>https://gitlab.dev.appstract.dk/internal/umbracocontactnumber</PackageProjectUrl>
		<RepositoryUrl>https://gitlab.dev.appstract.dk/internal/umbracocontactnumber</RepositoryUrl>
		<PackageRequireLicenseAcceptance>false</PackageRequireLicenseAcceptance>
		<Description>
46
47
48
			This adds a contact (phone) number custom property editor that allows to select a country code
			from a list of countries and shows a green checkbox if the number is known to be of correct
			length for the country.
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
		</Description>
		<PackageReleaseNotes>Initial release with hardcoded country database.</PackageReleaseNotes>
		<Copyright>Copyright 2020</Copyright>
		<PackageTags>umbraco;umbraco-cms;custom-property-editor;contact-number</PackageTags>
		<PackageIcon>images\icon.png</PackageIcon>
		<PackageIconUrl>https://appstract.dk/dist/images/apple-touch-icon.png</PackageIconUrl>
		<ContentTargetFolders>content</ContentTargetFolders>
		...
	</PropertyGroup>
	...
</Project>
```

To include the custom property editor in the NuGet package, the following items are included with `Pack="true"`:

```xml
<Project ...>
	...
	<ItemGroup>
		<Content Include="App_Plugins\Appstract.UmbracoContactNumber\**\*.*" Pack="true" />
		<None Include="..\.editorconfig" Link=".editorconfig" />
		<None Include="Appstract-a Logo.png" Pack="true" PackagePath="images\icon.png" />
		...
	</ItemGroup>
	...
</Project>
```

77
## How to build the Umbraco package
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
An MSBuild target that builds the Umbraco package has been defined to run after the build completes.

The targets file is imported as follows:

```xml
<Project ...>
	...
	<Import Project="../UmbracoPackage.targets" />
</Project>
```

As input it takes an `Item` element of the name `UmbracoPackageContent`.
In the project file, files are included into the Umbraco package by using the following syntax:

```xml
<Project ...>
	...
	<ItemGroup>
		...
		<UmbracoPackageContent Include="App_Plugins\Appstract.UmbracoContactNumber\**\*.*" />
		<UmbracoPackageContent Include="$(OutputPath)\$(AssemblyName).dll" />
		<UmbracoPackageContent Include="package.xml" />
	</ItemGroup>
	...
</Project>
```

Here, `App_Plugins\Appstract.UmbracoContactNumber\**\*.*` means take all files with extensions that are located below `App_Plugins\Appstract.UmbracoContactNumber\`.

#### The Umbraco package structure
The Umbraco package is a zip-file consisting of a manifest called `package.xml` and the files to include in the package.
In this case, the files to include is the compiled `Appstract.UmbracoContactNumber.dll` as well as the custom property editor located in `App_Plugins\Appstract.UmbracoContactNumber`.

The manifest has a `<file>` element for each of the included files, which specifies the source (in the package) as well as where the file should be located when installed (both path and name, in case two folders contain a file with the same name).

Furthermore the manifest has some metadata that describes the package itself in terms of name, version, license, required Umbraco version, readme and so on.

It is also possible to create Umbraco data on install. In this case we create a default data type instance of the custom property editor by adding an element to the `<DataTypes>` element. Since the custom property editor has no configuration for now, it's just consisting of a name, an id, a GUID, and a database type.

117
### MSBuild target definitions walkthrough
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
Source: `UmbracoPackage.targets`.

The first property group defines an intermediate folder where the contents of the Umbraco package:

```xml
<Project ...>
	<PropertyGroup Condition=" '$(UmbracoPackageIntermediateOutputPath)' == '' ">
		<UmbracoPackageIntermediateOutputPath>$(BaseIntermediateOutputPath)\umbracopackage_staging\</UmbracoPackageIntermediateOutputPath>
	</PropertyGroup>
	...
</Project>
```

By using `Condition` it is possible to override the intermediate output folder on a per-project basis.
This is useful if multiple projects create different Umbraco Packages.

If not overridden, it defaults to `$(BaseIntermediateOutputPath)\umbracopackage_staging\` which usually resolves to `obj\umbracopackage_staging\`.

136
#### UmbracoPackage
137
138
139
140
141
142
143
144
145
146
The first target `UmbracoPackage` is set up to run after a build, and only if the input files have changed with respect to the resulting Umbraco package file.

It has the following steps:

1. Create the `$(UmbracoPackageIntermediateOutputPath)` folder if it doesn't exist.
2. Remove all files from `$(UmbracoPackageIntermediateOutputPath)`. This is to avoid packaging files that should have been removed from the package.
3. Copy all items from `@(UmbracoPackageContent)` into `$(UmbracoPackageIntermediateOutputPath)` without keeping the folder structure.
4. Change the version in the `package.xml` to follow the MSBuild Version property. Note that only the `package.xml` in `$(UmbracoPackageIntermediateOutputPath)` is changed, not the source file.
5. Zip `$(UmbracoPackageIntermediateOutputPath)` into a package, and place it in `$(BaseOutputPath)\$(Configuration)\$(AssemblyName).$(Version).zip`, overwriting any existing file. `$(BaseOutputPath)\$(Configuration)\$(AssemblyName).$(Version).zip` usually resolves to `bin\Release\Appstract.UmbracoContactNumber.1.0.0.zip`. This folder is also where the NuGet package is stored.

147
#### UmbracoPackageClean
148
149
The second target `UmbracoPackageClean` is set up to run after cleaning the project. It removes the contents of `$(UmbracoPackageIntermediateOutputPath)` as well as the containing folder.

150
### Roadmap
151
152
153
154
If we make many of these packages in the future, it might be worthwhile spending some time on creating an actual Umbraco Package task, that takes the files and metadata as input, and creates the packages.xml from scratch, rather than relying on it being well-formed.

MSBuild tasks can be written in .NET and distributed as NuGet packages, such that this can be easily imported into other projects.

155
156
157
158
159
160
161
162
163
164
165
166
The downside to doing this, is that Umbraco can change the format without notice - so it would be great if they distributed such an opportunity alongside Umbraco itself.

# Known Issues
* Editor does not correctly report validity.
	* If the number field has been filled, but is now manually emptied, the editor will show a red warning saying that the property value is invalid.
	* If the property has been marked as required, the editor still allows a deleted value, as it fills out `$scope.model.value` with a default of
		```json
		{
			"CountryCodeAndPhoneCode": "#",
			"ContactNumber": ""
		}
		```