Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fd2fe1939a | |||
| 81e56bed9e | |||
| 52457fea21 | |||
| 07ec9aa813 | |||
| ba89aec34f | |||
| 29533820ab | |||
| 4366500fad | |||
| ee6e1a9d8b | |||
| 3b95184f04 | |||
| 9da7e108da | |||
| cb491d45ab | |||
| 344b880ba7 | |||
| c958f12bc1 | |||
| 9a973d0ccc | |||
| b170053e87 | |||
| db4509de2b | |||
| 5c91b822e3 | |||
| e6ddf63e56 | |||
| 84ac029372 | |||
| 5d59741612 | |||
| 2ffd0413e8 | |||
| dc4e6ee01c | |||
| 1d8e217c6f | |||
| 0b3136cf20 | |||
| b0e96b256a | |||
| 72a966b0fa | |||
| bf222f26cd | |||
| be9f4b70e2 | |||
| 0060f0019e | |||
| 632cd221d9 | |||
| 46d5215d9e | |||
| aa43656cb9 | |||
| e4837d1962 | |||
| 40868d7cd2 | |||
| 0fde3f7b5d | |||
| 76f0eac5f8 | |||
| 2352d258b9 | |||
| 2dc38a29cf | |||
| 1aa162e255 | |||
| 342999a678 | |||
| 5cb210c7b6 | |||
| b80ab20cb4 | |||
| bac6e71e7f | |||
| 9a36d74418 | |||
| 39eaa4a15e | |||
| 2fdf040f73 | |||
| aec956dd2e | |||
| 65bb1e1e20 | |||
| 3dabd73ec2 | |||
| 90e5440518 | |||
| 7cfd2d6593 | |||
| 6382515258 | |||
| fd2b9ce67d | |||
| 1284417a58 | |||
| b57642003c | |||
| 9ee59e8e38 | |||
| a5f81ae6c2 | |||
| 08cc608dc8 | |||
| 71839d53a6 | |||
| 7508613d13 | |||
| 9626e91c83 | |||
| 83b6375f04 | |||
| 52cd44a700 | |||
| 0c8ff187aa | |||
| 3af74bd4fd | |||
| c9e2e1e116 | |||
| c27f73e54a | |||
| cede13d180 | |||
| 3ffb2772b6 | |||
| e6f0d4e056 | |||
| 23c7eafaf5 | |||
| 90892ce818 | |||
| e62d1559b1 | |||
| 81934c47d2 | |||
| 80379e116d | |||
| 89081b86af | |||
| 216e2255f2 | |||
| 9db3dbd730 | |||
| 8a1dd96294 | |||
| 67bebd0d2d | |||
| 4f34fbd2c8 | |||
| 8cda6e4062 | |||
| d8209efefa | |||
| 00180d2120 | |||
| 66e768afee | |||
| bba109cb28 | |||
| 39ede8c47a | |||
| fec84b8ce3 | |||
| a00e5d54aa | |||
| 331813e370 | |||
| 6c36f43276 | |||
| e8f4e7663f | |||
| 9f116c00d5 | |||
| 7e61b25746 | |||
| 482750ab6a | |||
| 40d1099fbd | |||
| 2d050a0c88 | |||
| 103f4f33bd | |||
| 727f9355a0 | |||
| e269a0b9bb | |||
| 861b1cefe5 | |||
| 23301817bf | |||
| f5842c82a6 | |||
| 4baf3ed99a | |||
| 3c09cd7674 |
@@ -78,6 +78,12 @@ src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/loader.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/main.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/app.js
|
||||
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.panel.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.palettes.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.loader.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.front.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Jj]s/tuning.config.js
|
||||
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.js
|
||||
src/Umbraco.Web.UI/[Uu]mbraco/[Vv]iews/**/*.css
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ IF NOT EXIST UmbracoVersion.txt (
|
||||
GOTO :showerror
|
||||
)
|
||||
SET /p release=<UmbracoVersion.txt
|
||||
SET comment=
|
||||
SET comment=alpha
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
@@ -1 +1 @@
|
||||
7.1.5
|
||||
7.2.0
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.1.5");
|
||||
private static readonly Version Version = new Version("7.2.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
public static string CurrentComment { get { return "alpha"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -70,6 +70,11 @@
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
|
||||
/// <summary>
|
||||
/// alias for the media tree.
|
||||
/// </summary>
|
||||
public const string Templates = "template";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -130,6 +130,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string FolderBrowserAlias = "Umbraco.FolderBrowser";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the grid datatype.
|
||||
/// </summary>
|
||||
public const string GridAlias = "Umbraco.Grid";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Image Cropper datatype.
|
||||
/// </summary>
|
||||
|
||||
@@ -93,8 +93,17 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
if (ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
var contentTypeComposition = ContentTypeComposition.FirstOrDefault(x => x.Alias == alias);
|
||||
if (contentTypeComposition == null)//You can't remove a composition from another composition
|
||||
return false;
|
||||
|
||||
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
|
||||
|
||||
//If the ContentType we are removing has Compositions of its own these needs to be removed as well
|
||||
var compositionIdsToRemove = contentTypeComposition.CompositionIds().ToList();
|
||||
if(compositionIdsToRemove.Any())
|
||||
RemovedContentTypeKeyTracker.AddRange(compositionIdsToRemove);
|
||||
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
return _contentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
var nodeId = contentDto.NodeId;
|
||||
var propertyTypeId = propertyType.Id;
|
||||
var propertySql = new Sql().Select("*")
|
||||
var propertySql = new Sql().Select("cmsPropertyData.id")
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyDataDto, PropertyTypeDto>(
|
||||
@@ -249,7 +249,7 @@ AND umbracoNode.id <> @id",
|
||||
.Where<PropertyTypeDto>(x => x.Id == propertyTypeId);
|
||||
|
||||
//Finally delete the properties that match our criteria for removing a ContentType from the composition
|
||||
Database.Delete<PropertyDataDto>(propertySql);
|
||||
Database.Delete<PropertyDataDto>(new Sql("WHERE id IN (" + propertySql.SQL + ")", propertySql.Arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -285,7 +285,8 @@ AND umbracoNode.id <> @id",
|
||||
}
|
||||
}
|
||||
|
||||
if (((ICanBeDirty) entity).IsPropertyDirty("PropertyGroups") || entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("PropertyGroups") ||
|
||||
entity.PropertyGroups.Any(x => x.IsDirty()))
|
||||
{
|
||||
//Delete Tabs/Groups by excepting entries from db with entries from collections
|
||||
var dbPropertyGroups =
|
||||
@@ -346,6 +347,25 @@ AND umbracoNode.id <> @id",
|
||||
if (propertyType.HasIdentity == false)
|
||||
propertyType.Id = typePrimaryKey; //Set Id on new PropertyType
|
||||
}
|
||||
|
||||
//If a Composition is removed we need to update/reset references to the PropertyGroups on that ContentType
|
||||
if (((ICanBeDirty)entity).IsPropertyDirty("ContentTypeComposition") &&
|
||||
compositionBase != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker != null &&
|
||||
compositionBase.RemovedContentTypeKeyTracker.Any())
|
||||
{
|
||||
foreach (var compositionId in compositionBase.RemovedContentTypeKeyTracker)
|
||||
{
|
||||
var dbPropertyGroups =
|
||||
Database.Fetch<PropertyTypeGroupDto>("WHERE contenttypeNodeId = @Id", new { Id = compositionId })
|
||||
.Select(x => x.Id);
|
||||
foreach (var propertyGroup in dbPropertyGroups)
|
||||
{
|
||||
Database.Update<PropertyTypeGroupDto>("SET parentGroupId = NULL WHERE parentGroupId = @TabId AND contenttypeNodeId = @ContentTypeNodeId",
|
||||
new { TabId = propertyGroup, ContentTypeNodeId = entity.Id });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected IEnumerable<ContentTypeSort> GetAllowedContentTypeIds(int id)
|
||||
|
||||
@@ -371,7 +371,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//template.CreateDate = _viewsFileSystem.GetCreated(path).UtcDateTime;
|
||||
//template.Key = new FileInfo(path).Name.EncodeAsGuid();
|
||||
|
||||
template.Path = path;
|
||||
template.Content = content;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"typeahead.js": "~0.10.2"
|
||||
"typeahead.js": "~0.10.2",
|
||||
"ace-builds": "~1.1.3",
|
||||
"rgrove-lazyload": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,15 +6,16 @@ module.exports = function (grunt) {
|
||||
grunt.registerTask('dev', ['jshint:dev', 'build', 'webserver', 'open:dev', 'watch']);
|
||||
|
||||
//run by the watch task
|
||||
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:vs','karma:unit']);
|
||||
grunt.registerTask('watch-less', ['recess:build','recess:installer','copy:assets','copy:vs']);
|
||||
grunt.registerTask('watch-js', ['jshint:dev','concat','copy:app','copy:mocks','copy:packages','copy:tuning','copy:vs','karma:unit']);
|
||||
grunt.registerTask('watch-less', ['recess:build', 'recess:installer', 'recess:tuning','copy:tuning', 'copy:assets', 'copy:vs']);
|
||||
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
|
||||
grunt.registerTask('watch-packages', ['copy:packages']);
|
||||
grunt.registerTask('watch-installer', ['concat:install','concat:installJs','copy:installer', 'copy:vs']);
|
||||
grunt.registerTask('watch-installer', ['concat:install', 'concat:installJs', 'copy:installer', 'copy:vs']);
|
||||
grunt.registerTask('watch-tuning', ['copy:tuning', 'concat:tuningJs', 'copy:vs']);
|
||||
grunt.registerTask('watch-test', ['jshint:dev', 'karma:unit']);
|
||||
|
||||
//triggered from grunt dev or grunt
|
||||
grunt.registerTask('build', ['clean','concat','recess:min','recess:installer','copy']);
|
||||
grunt.registerTask('build', ['clean', 'concat', 'recess:min', 'recess:installer', 'recess:tuning', 'bower', 'copy']);
|
||||
|
||||
//utillity tasks
|
||||
grunt.registerTask('docs', ['ngdocs']);
|
||||
@@ -109,23 +110,48 @@ module.exports = function (grunt) {
|
||||
clean: ['<%= distdir %>/*'],
|
||||
|
||||
copy: {
|
||||
|
||||
/* Copies over the files downloaded by bower
|
||||
bower: {
|
||||
files: [
|
||||
{ dest: '<%= distdir %>/lib/typeahead/typeahead.bundle.min.js', src: '<%= bowerfiles %>/typeahead.js/dist/typeahead.bundle.min.js' }
|
||||
]
|
||||
},
|
||||
*/
|
||||
|
||||
assets: {
|
||||
files: [{ dest: '<%= distdir %>/assets', src : '**', expand: true, cwd: 'src/assets/' }]
|
||||
},
|
||||
|
||||
|
||||
// Copies over the files downloaded by bower
|
||||
bower: {
|
||||
files: [
|
||||
{
|
||||
dest: '<%= distdir %>/lib/typeahead/typeahead.bundle.min.js',
|
||||
src: 'bower_components/typeahead.js/dist/typeahead.bundle.min.js'
|
||||
},
|
||||
{
|
||||
dest: '<%= distdir %>/lib/lazyload/lazyload.min.js',
|
||||
src: 'bower_components/rgrove-lazyload/lazyload.js'
|
||||
},
|
||||
{
|
||||
dest: '<%= distdir %>/lib/ace/',
|
||||
src: '**',
|
||||
expand: true,
|
||||
cwd: 'bower_components/ace-builds/src-min-noconflict/'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
installer: {
|
||||
files: [{ dest: '<%= distdir %>/views/install', src : '**/*.html', expand: true, cwd: 'src/installer/steps' }]
|
||||
},
|
||||
|
||||
tuning: {
|
||||
files: [
|
||||
{ dest: '<%= distdir %>/preview', src: '**/*.html', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/css', src: 'tuning.defaultStyle.css', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/less', src: 'tuning.defaultStyle.less', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/assets/less', src: 'tuning.gridRowStyle.less', expand: true, cwd: 'src/tuning' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.config.js', expand: true, cwd: 'src/tuning/config' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.palettes.js', expand: true, cwd: 'src/tuning/config' },
|
||||
{ dest: '<%= distdir %>/js', src: 'tuning.front.js', expand: true, cwd: 'src/tuning' }
|
||||
]
|
||||
},
|
||||
|
||||
vendor: {
|
||||
files: [{ dest: '<%= distdir %>/lib', src : '**', expand: true, cwd: 'lib/' }]
|
||||
},
|
||||
@@ -147,7 +173,8 @@ module.exports = function (grunt) {
|
||||
{ dest: '<%= vsdir %>/assets', src: '**', expand: true, cwd: '<%= distdir %>/assets' },
|
||||
{ dest: '<%= vsdir %>/js', src: '**', expand: true, cwd: '<%= distdir %>/js' },
|
||||
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' },
|
||||
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' }
|
||||
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
|
||||
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' }
|
||||
]
|
||||
},
|
||||
|
||||
@@ -186,6 +213,10 @@ module.exports = function (grunt) {
|
||||
footer: "\n\n})();"
|
||||
}
|
||||
},
|
||||
tuningJs: {
|
||||
src: ['src/tuning/tuning.global.js', 'src/tuning/tuning.controller.js', 'src/tuning/lib/slider.directive.js', 'src/tuning/lib/spectrum.directive.js'],
|
||||
dest: '<%= distdir %>/js/tuning.panel.js'
|
||||
},
|
||||
controllers: {
|
||||
src:['src/controllers/**/*.controller.js','src/views/**/*.controller.js'],
|
||||
dest: '<%= distdir %>/js/umbraco.controllers.js',
|
||||
@@ -272,6 +303,15 @@ module.exports = function (grunt) {
|
||||
compile: true
|
||||
}
|
||||
},
|
||||
tuning: {
|
||||
files: {
|
||||
'<%= distdir %>/assets/css/tuning.panelStyles.css':
|
||||
['src/less/tuning.panelStyles.less', 'src/less/helveticons.less']
|
||||
},
|
||||
options: {
|
||||
compile: true
|
||||
}
|
||||
},
|
||||
min: {
|
||||
files: {
|
||||
'<%= distdir %>/assets/css/<%= pkg.name %>.css': ['<%= src.less %>']
|
||||
@@ -304,6 +344,10 @@ module.exports = function (grunt) {
|
||||
files: ['src/installer/**/*.*'],
|
||||
tasks: ['watch-installer', 'timestamp'],
|
||||
},
|
||||
tuning: {
|
||||
files: ['src/tuning/**/*.*'],
|
||||
tasks: ['watch-tuning', 'timestamp'],
|
||||
},
|
||||
html: {
|
||||
files: ['src/views/**/*.html', 'src/*.html'],
|
||||
tasks:['watch-html','timestamp']
|
||||
|
||||
+9
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
|
||||
// Inline and block code styles
|
||||
code,
|
||||
pre {
|
||||
pre.code {
|
||||
padding: 0 3px 2px;
|
||||
#font > #family > .monospace;
|
||||
font-size: @baseFontSize - 2;
|
||||
@@ -23,7 +23,7 @@ code {
|
||||
}
|
||||
|
||||
// Blocks of code
|
||||
pre {
|
||||
pre.code {
|
||||
display: block;
|
||||
padding: (@baseLineHeight - 1) / 2;
|
||||
margin: 0 0 @baseLineHeight / 2;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,4 +0,0 @@
|
||||
LazyLoad=function(x,h){function r(b,a){var c=h.createElement(b),d;for(d in a)a.hasOwnProperty(d)&&c.setAttribute(d,a[d]);return c}function k(b){var a=i[b],c,d;if(a){c=a.callback;d=a.urls;d.shift();l=0;if(!d.length){c&&c.call(a.context,a.obj);i[b]=null;j[b].length&&m(b)}}}function w(){if(!e){var b=navigator.userAgent;e={async:h.createElement("script").async===true};(e.webkit=/AppleWebKit\//.test(b))||(e.ie=/MSIE/.test(b))||(e.opera=/Opera/.test(b))||(e.gecko=/Gecko\//.test(b))||(e.unknown=true)}}function m(b,
|
||||
a,c,d,s){var n=function(){k(b)},o=b==="css",f,g,p;w();if(a){a=typeof a==="string"?[a]:a.concat();if(o||e.async||e.gecko||e.opera)j[b].push({urls:a,callback:c,obj:d,context:s});else{f=0;for(g=a.length;f<g;++f)j[b].push({urls:[a[f]],callback:f===g-1?c:null,obj:d,context:s})}}if(!(i[b]||!(p=i[b]=j[b].shift()))){q||(q=h.head||h.getElementsByTagName("head")[0]);a=p.urls;f=0;for(g=a.length;f<g;++f){c=a[f];if(o)c=r("link",{charset:"utf-8","class":"lazyload",href:c,rel:"stylesheet",type:"text/css"});else{c=
|
||||
r("script",{charset:"utf-8","class":"lazyload",src:c});c.async=false}if(e.ie)c.onreadystatechange=function(){var t=this.readyState;if(t==="loaded"||t==="complete"){this.onreadystatechange=null;n()}};else if(o&&(e.gecko||e.webkit))if(e.webkit){p.urls[f]=c.href;u()}else setTimeout(n,50*g);else c.onload=c.onerror=n;q.appendChild(c)}}}function u(){var b=i.css,a;if(b){for(a=v.length;a&&--a;)if(v[a].href===b.urls[0]){k("css");break}l+=1;if(b)l<200?setTimeout(u,50):k("css")}}var e,q,i={},l=0,j={css:[],js:[]},
|
||||
v=h.styleSheets;return{css:function(b,a,c,d){m("css",b,a,c,d)},js:function(b,a,c,d){m("js",b,a,c,d)}}}(this,this.document);
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -335,6 +335,10 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
|
||||
this._modal.push(dialog);
|
||||
return dialog;
|
||||
},
|
||||
rootScope : function(){
|
||||
return getRootScope();
|
||||
},
|
||||
|
||||
closeModalWindow: function(rVal) {
|
||||
|
||||
//get our angular navigation service
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 763 KiB After Width: | Height: | Size: 116 KiB |
@@ -0,0 +1,269 @@
|
||||
angular.module('umbraco')
|
||||
.constant('uiAceConfig', {})
|
||||
.directive('uiAce', ['uiAceConfig', function (uiAceConfig) {
|
||||
|
||||
if (angular.isUndefined(window.ace)) {
|
||||
throw new Error('ui-ace need ace to work... (o rly?)');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets editor options such as the wrapping mode or the syntax checker.
|
||||
*
|
||||
* The supported options are:
|
||||
*
|
||||
* <ul>
|
||||
* <li>showGutter</li>
|
||||
* <li>useWrapMode</li>
|
||||
* <li>onLoad</li>
|
||||
* <li>theme</li>
|
||||
* <li>mode</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param acee
|
||||
* @param session ACE editor session
|
||||
* @param {object} opts Options to be set
|
||||
*/
|
||||
var setOptions = function(acee, session, opts) {
|
||||
|
||||
// Boolean options
|
||||
if (angular.isDefined(opts.showGutter)) {
|
||||
acee.renderer.setShowGutter(opts.showGutter);
|
||||
}
|
||||
if (angular.isDefined(opts.useWrapMode)) {
|
||||
session.setUseWrapMode(opts.useWrapMode);
|
||||
}
|
||||
if (angular.isDefined(opts.showInvisibles)) {
|
||||
acee.renderer.setShowInvisibles(opts.showInvisibles);
|
||||
}
|
||||
if (angular.isDefined(opts.showIndentGuides)) {
|
||||
acee.renderer.setDisplayIndentGuides(opts.showIndentGuides);
|
||||
}
|
||||
if (angular.isDefined(opts.useSoftTabs)) {
|
||||
session.setUseSoftTabs(opts.useSoftTabs);
|
||||
}
|
||||
|
||||
// commands
|
||||
if (angular.isDefined(opts.disableSearch) && opts.disableSearch) {
|
||||
acee.commands.addCommands([
|
||||
{
|
||||
name: 'unfind',
|
||||
bindKey: {
|
||||
win: 'Ctrl-F',
|
||||
mac: 'Command-F'
|
||||
},
|
||||
exec: function () {
|
||||
return false;
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// onLoad callback
|
||||
if (angular.isFunction(opts.onLoad)) {
|
||||
opts.onLoad(acee);
|
||||
}
|
||||
|
||||
// Basic options
|
||||
if (angular.isString(opts.theme)) {
|
||||
acee.setTheme('ace/theme/' + opts.theme);
|
||||
}
|
||||
if (angular.isString(opts.mode)) {
|
||||
session.setMode('ace/mode/' + opts.mode);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
require: '?ngModel',
|
||||
link: function (scope, elm, attrs, ngModel) {
|
||||
|
||||
/**
|
||||
* Corresponds the uiAceConfig ACE configuration.
|
||||
* @type object
|
||||
*/
|
||||
var options = uiAceConfig.ace || {};
|
||||
|
||||
/**
|
||||
* uiAceConfig merged with user options via json in attribute or data binding
|
||||
* @type object
|
||||
*/
|
||||
var opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
|
||||
|
||||
/**
|
||||
* ACE editor
|
||||
* @type object
|
||||
*/
|
||||
var acee = window.ace.edit(elm[0]);
|
||||
|
||||
/**
|
||||
* ACE editor session.
|
||||
* @type object
|
||||
* @see [EditSession]{@link http://ace.c9.io/#nav=api&api=edit_session}
|
||||
*/
|
||||
var session = acee.getSession();
|
||||
|
||||
/**
|
||||
* Reference to a change listener created by the listener factory.
|
||||
* @function
|
||||
* @see listenerFactory.onChange
|
||||
*/
|
||||
var onChangeListener;
|
||||
|
||||
/**
|
||||
* Reference to a blur listener created by the listener factory.
|
||||
* @function
|
||||
* @see listenerFactory.onBlur
|
||||
*/
|
||||
var onBlurListener;
|
||||
|
||||
/**
|
||||
* Calls a callback by checking its existing. The argument list
|
||||
* is variable and thus this function is relying on the arguments
|
||||
* object.
|
||||
* @throws {Error} If the callback isn't a function
|
||||
*/
|
||||
var executeUserCallback = function () {
|
||||
|
||||
/**
|
||||
* The callback function grabbed from the array-like arguments
|
||||
* object. The first argument should always be the callback.
|
||||
*
|
||||
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
|
||||
* @type {*}
|
||||
*/
|
||||
var callback = arguments[0];
|
||||
|
||||
/**
|
||||
* Arguments to be passed to the callback. These are taken
|
||||
* from the array-like arguments object. The first argument
|
||||
* is stripped because that should be the callback function.
|
||||
*
|
||||
* @see [arguments]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions_and_function_scope/arguments}
|
||||
* @type {Array}
|
||||
*/
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
|
||||
if (angular.isDefined(callback)) {
|
||||
scope.$apply(function () {
|
||||
if (angular.isFunction(callback)) {
|
||||
callback(args);
|
||||
} else {
|
||||
throw new Error('ui-ace use a function as callback.');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Listener factory. Until now only change listeners can be created.
|
||||
* @type object
|
||||
*/
|
||||
var listenerFactory = {
|
||||
/**
|
||||
* Creates a change listener which propagates the change event
|
||||
* and the editor session to the callback from the user option
|
||||
* onChange. It might be exchanged during runtime, if this
|
||||
* happens the old listener will be unbound.
|
||||
*
|
||||
* @param callback callback function defined in the user options
|
||||
* @see onChangeListener
|
||||
*/
|
||||
onChange: function (callback) {
|
||||
return function (e) {
|
||||
var newValue = session.getValue();
|
||||
if (newValue !== scope.$eval(attrs.value) && !scope.$$phase && !scope.$root.$$phase) {
|
||||
if (angular.isDefined(ngModel)) {
|
||||
scope.$apply(function () {
|
||||
ngModel.$setViewValue(newValue);
|
||||
});
|
||||
}
|
||||
executeUserCallback(callback, e, acee);
|
||||
}
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Creates a blur listener which propagates the editor session
|
||||
* to the callback from the user option onBlur. It might be
|
||||
* exchanged during runtime, if this happens the old listener
|
||||
* will be unbound.
|
||||
*
|
||||
* @param callback callback function defined in the user options
|
||||
* @see onBlurListener
|
||||
*/
|
||||
onBlur: function (callback) {
|
||||
return function () {
|
||||
executeUserCallback(callback, acee);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
attrs.$observe('readonly', function (value) {
|
||||
acee.setReadOnly(value === 'true');
|
||||
});
|
||||
|
||||
// Value Blind
|
||||
if (angular.isDefined(ngModel)) {
|
||||
ngModel.$formatters.push(function (value) {
|
||||
if (angular.isUndefined(value) || value === null) {
|
||||
return '';
|
||||
}
|
||||
else if (angular.isObject(value) || angular.isArray(value)) {
|
||||
throw new Error('ui-ace cannot use an object or an array as a model');
|
||||
}
|
||||
return value;
|
||||
});
|
||||
|
||||
ngModel.$render = function () {
|
||||
session.setValue(ngModel.$viewValue);
|
||||
};
|
||||
}
|
||||
|
||||
// set the options here, even if we try to watch later, if this
|
||||
// line is missing things go wrong (and the tests will also fail)
|
||||
setOptions(acee, session, opts);
|
||||
|
||||
// Listen for option updates
|
||||
scope.$watch( attrs.uiAce, function() {
|
||||
opts = angular.extend({}, options, scope.$eval(attrs.uiAce));
|
||||
|
||||
// unbind old change listener
|
||||
session.removeListener('change', onChangeListener);
|
||||
|
||||
// bind new change listener
|
||||
onChangeListener = listenerFactory.onChange(opts.onChange);
|
||||
session.on('change', onChangeListener);
|
||||
|
||||
// unbind old blur listener
|
||||
//session.removeListener('blur', onBlurListener);
|
||||
acee.removeListener('blur', onBlurListener);
|
||||
|
||||
// bind new blur listener
|
||||
onBlurListener = listenerFactory.onBlur(opts.onBlur);
|
||||
acee.on('blur', onBlurListener);
|
||||
|
||||
setOptions(acee, session, opts);
|
||||
}, /* deep watch */ true );
|
||||
|
||||
// EVENTS
|
||||
onChangeListener = listenerFactory.onChange(opts.onChange);
|
||||
session.on('change', onChangeListener);
|
||||
|
||||
onBlurListener = listenerFactory.onBlur(opts.onBlur);
|
||||
acee.on('blur', onBlurListener);
|
||||
|
||||
elm.on('$destroy', function () {
|
||||
acee.session.$stopWorker();
|
||||
acee.destroy();
|
||||
});
|
||||
|
||||
scope.$watch(function() {
|
||||
return [elm[0].offsetWidth, elm[0].offsetHeight];
|
||||
}, function() {
|
||||
acee.resize();
|
||||
acee.renderer.updateFull();
|
||||
}, true);
|
||||
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -0,0 +1,283 @@
|
||||
angular.module("umbraco")
|
||||
.directive('gridRte', function (tinyMceService, stylesheetResource, angularHelper, assetsService, $q, $timeout) {
|
||||
return {
|
||||
scope: {
|
||||
uniqueId: '=',
|
||||
value: '=',
|
||||
onClick: '&',
|
||||
onFocus: '&',
|
||||
onBlur: '&',
|
||||
configuration:"="
|
||||
},
|
||||
template: "<textarea ng-model=\"value\" rows=\"10\" class=\"mceNoEditor\" id=\"{{uniqueId}}\"></textarea>",
|
||||
replace: true,
|
||||
link: function (scope, element, attrs) {
|
||||
|
||||
var initTiny = function () {
|
||||
|
||||
//we always fetch the default one, and then override parts with our own
|
||||
tinyMceService.configuration().then(function (tinyMceConfig) {
|
||||
|
||||
|
||||
|
||||
//config value from general tinymce.config file
|
||||
var validElements = tinyMceConfig.validElements;
|
||||
var fallbackStyles = [{title: "Page header", block: "h2"}, {title: "Section header", block: "h3"}, {title: "Paragraph header", block: "h4"}, {title: "Normal", block: "p"}, {title: "Quote", block: "blockquote"}, {title: "Code", block: "code"}];
|
||||
|
||||
//These are absolutely required in order for the macros to render inline
|
||||
//we put these as extended elements because they get merged on top of the normal allowed elements by tiny mce
|
||||
var extendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align]";
|
||||
|
||||
var invalidElements = tinyMceConfig.inValidElements;
|
||||
var plugins = _.map(tinyMceConfig.plugins, function (plugin) {
|
||||
if (plugin.useOnFrontend) {
|
||||
return plugin.name;
|
||||
}
|
||||
}).join(" ") + " autoresize";
|
||||
|
||||
//config value on the data type
|
||||
var toolbar = ["code", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbembeddialog"].join(" | ");
|
||||
var stylesheets = [];
|
||||
|
||||
var styleFormats = [];
|
||||
var await = [];
|
||||
|
||||
//queue file loading
|
||||
if (typeof (tinymce) === "undefined") {
|
||||
await.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope));
|
||||
}
|
||||
|
||||
|
||||
if(scope.configuration && scope.configuration.toolbar){
|
||||
toolbar = scope.configuration.toolbar.join(' | ');
|
||||
}
|
||||
|
||||
|
||||
if(scope.configuration && scope.configuration.stylesheets){
|
||||
angular.forEach(scope.configuration.stylesheets, function(stylesheet, key){
|
||||
|
||||
stylesheets.push("/css/" + stylesheet + ".css");
|
||||
await.push(stylesheetResource.getRulesByName(stylesheet).then(function (rules) {
|
||||
angular.forEach(rules, function (rule) {
|
||||
var r = {};
|
||||
r.title = rule.name;
|
||||
if (rule.selector[0] === ".") {
|
||||
r.inline = "span";
|
||||
r.classes = rule.selector.substring(1);
|
||||
}else if (rule.selector[0] === "#") {
|
||||
r.inline = "span";
|
||||
r.attributes = { id: rule.selector.substring(1) };
|
||||
}else {
|
||||
r.block = rule.selector;
|
||||
}
|
||||
styleFormats.push(r);
|
||||
});
|
||||
}));
|
||||
});
|
||||
}else{
|
||||
stylesheets.push("views/propertyeditors/grid/config/grid.default.rtestyles.css");
|
||||
styleFormats = fallbackStyles;
|
||||
}
|
||||
|
||||
//stores a reference to the editor
|
||||
var tinyMceEditor = null;
|
||||
$q.all(await).then(function () {
|
||||
|
||||
var uniqueId = scope.uniqueId;
|
||||
|
||||
//create a baseline Config to exten upon
|
||||
var baseLineConfigObj = {
|
||||
mode: "exact",
|
||||
skin: "umbraco",
|
||||
plugins: plugins,
|
||||
valid_elements: validElements,
|
||||
invalid_elements: invalidElements,
|
||||
extended_valid_elements: extendedValidElements,
|
||||
menubar: false,
|
||||
statusbar: false,
|
||||
relative_urls: false,
|
||||
autoresize_min_height: 30,
|
||||
toolbar: toolbar,
|
||||
content_css: stylesheets.join(','),
|
||||
style_formats: styleFormats
|
||||
};
|
||||
|
||||
|
||||
if (tinyMceConfig.customConfig) {
|
||||
angular.extend(baseLineConfigObj, tinyMceConfig.customConfig);
|
||||
}
|
||||
|
||||
//set all the things that user configs should not be able to override
|
||||
baseLineConfigObj.elements = uniqueId;
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
|
||||
|
||||
//enable browser based spell checking
|
||||
editor.on('init', function (e) {
|
||||
editor.getBody().setAttribute('spellcheck', true);
|
||||
|
||||
//hide toolbar by default
|
||||
$(editor.editorContainer)
|
||||
.find(".mce-toolbar")
|
||||
.css("visibility", "hidden");
|
||||
|
||||
$timeout(function(){
|
||||
if(scope.value === null){
|
||||
editor.focus();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
});
|
||||
|
||||
//when we leave the editor (maybe)
|
||||
editor.on('blur', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onBlur){
|
||||
scope.onBlur();
|
||||
}
|
||||
|
||||
_toolbar.css("visibility", "hidden");
|
||||
});
|
||||
});
|
||||
|
||||
// Focus on editor
|
||||
editor.on('focus', function (e) {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onFocus){
|
||||
scope.onFocus();
|
||||
}
|
||||
|
||||
var toolbarHeight = -_toolbar.height() - 2;
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("margin-top", toolbarHeight + "px");
|
||||
});
|
||||
});
|
||||
|
||||
// Click on editor
|
||||
editor.on('click', function (e) {
|
||||
angularHelper.safeApply(scope, function () {
|
||||
|
||||
var _toolbar = $(editor.editorContainer)
|
||||
.find(".mce-toolbar");
|
||||
|
||||
if(scope.onClick){
|
||||
scope.onClick();
|
||||
}
|
||||
|
||||
var toolbarHeight = -_toolbar.height() - 2;
|
||||
_toolbar
|
||||
.css("visibility", "visible")
|
||||
.css("margin-top", toolbarHeight + "px");
|
||||
});
|
||||
});
|
||||
|
||||
//when buttons modify content
|
||||
editor.on('ExecCommand', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
|
||||
// Update model on keypress
|
||||
editor.on('KeyUp', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
|
||||
// Update model on change, i.e. copy/pasted text, plugins altering content
|
||||
editor.on('SetContent', function (e) {
|
||||
if (!e.initial) {
|
||||
editor.save();
|
||||
angularHelper.safeApply(scope, function () {
|
||||
scope.value = editor.getContent();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
editor.on('ObjectResized', function (e) {
|
||||
var qs = "?width=" + e.width + "px&height=" + e.height + "px";
|
||||
var srcAttr = $(e.target).attr("src");
|
||||
var path = srcAttr.split("?")[0];
|
||||
$(e.target).attr("data-mce-src", path + qs);
|
||||
});
|
||||
|
||||
|
||||
//Create the insert media plugin
|
||||
tinyMceService.createMediaPicker(editor, scope);
|
||||
|
||||
//Create the embedded plugin
|
||||
tinyMceService.createInsertEmbeddedMedia(editor, scope);
|
||||
|
||||
//Create the insert link plugin
|
||||
//tinyMceService.createLinkPicker(editor, scope);
|
||||
|
||||
//Create the insert macro plugin
|
||||
tinyMceService.createInsertMacro(editor, scope);
|
||||
|
||||
};
|
||||
|
||||
/** Loads in the editor */
|
||||
function loadTinyMce() {
|
||||
|
||||
//we need to add a timeout here, to force a redraw so TinyMCE can find
|
||||
//the elements needed
|
||||
$timeout(function () {
|
||||
tinymce.DOM.events.domLoaded = true;
|
||||
tinymce.init(baseLineConfigObj);
|
||||
}, 150, false);
|
||||
}
|
||||
|
||||
loadTinyMce();
|
||||
|
||||
//here we declare a special method which will be called whenever the value has changed from the server
|
||||
//this is instead of doing a watch on the model.value = faster
|
||||
//scope.model.onValueChanged = function (newVal, oldVal) {
|
||||
// //update the display val again if it has changed from the server;
|
||||
// tinyMceEditor.setContent(newVal, { format: 'raw' });
|
||||
// //we need to manually fire this event since it is only ever fired based on loading from the DOM, this
|
||||
// // is required for our plugins listening to this event to execute
|
||||
// tinyMceEditor.fire('LoadContent', null);
|
||||
//};
|
||||
|
||||
//listen for formSubmitting event (the result is callback used to remove the event subscription)
|
||||
var unsubscribe = scope.$on("formSubmitting", function () {
|
||||
//TODO: Here we should parse out the macro rendered content so we can save on a lot of bytes in data xfer
|
||||
// we do parse it out on the server side but would be nice to do that on the client side before as well.
|
||||
scope.value = tinyMceEditor.getContent();
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
scope.$on('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
initTiny();
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,94 @@
|
||||
angular.module('umbraco.directives')
|
||||
.directive('checklistModel', ['$parse', '$compile', function($parse, $compile) {
|
||||
// contains
|
||||
function contains(arr, item) {
|
||||
if (angular.isArray(arr)) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// add
|
||||
function add(arr, item) {
|
||||
arr = angular.isArray(arr) ? arr : [];
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
arr.push(item);
|
||||
return arr;
|
||||
}
|
||||
|
||||
// remove
|
||||
function remove(arr, item) {
|
||||
if (angular.isArray(arr)) {
|
||||
for (var i = 0; i < arr.length; i++) {
|
||||
if (angular.equals(arr[i], item)) {
|
||||
arr.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/a/19228302/1458162
|
||||
function postLinkFn(scope, elem, attrs) {
|
||||
// compile with `ng-model` pointing to `checked`
|
||||
$compile(elem)(scope);
|
||||
|
||||
// getter / setter for original model
|
||||
var getter = $parse(attrs.checklistModel);
|
||||
var setter = getter.assign;
|
||||
|
||||
// value added to list
|
||||
var value = $parse(attrs.checklistValue)(scope.$parent);
|
||||
|
||||
// watch UI checked change
|
||||
scope.$watch('checked', function(newValue, oldValue) {
|
||||
if (newValue === oldValue) {
|
||||
return;
|
||||
}
|
||||
var current = getter(scope.$parent);
|
||||
if (newValue === true) {
|
||||
setter(scope.$parent, add(current, value));
|
||||
} else {
|
||||
setter(scope.$parent, remove(current, value));
|
||||
}
|
||||
});
|
||||
|
||||
// watch original model change
|
||||
scope.$parent.$watch(attrs.checklistModel, function(newArr, oldArr) {
|
||||
scope.checked = contains(newArr, value);
|
||||
}, true);
|
||||
}
|
||||
|
||||
return {
|
||||
restrict: 'A',
|
||||
priority: 1000,
|
||||
terminal: true,
|
||||
scope: true,
|
||||
compile: function(tElement, tAttrs) {
|
||||
if (tElement[0].tagName !== 'INPUT' || !tElement.attr('type', 'checkbox')) {
|
||||
throw 'checklist-model should be applied to `input[type="checkbox"]`.';
|
||||
}
|
||||
|
||||
if (!tAttrs.checklistValue) {
|
||||
throw 'You should provide `checklist-value`.';
|
||||
}
|
||||
|
||||
// exclude recursion
|
||||
tElement.removeAttr('checklist-model');
|
||||
|
||||
// local scope var storing individual checkbox model
|
||||
tElement.attr('ng-model', 'checked');
|
||||
|
||||
return postLinkFn;
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.resources.stylesheetResource
|
||||
* @description service to retrieve available stylesheets
|
||||
*
|
||||
*
|
||||
**/
|
||||
function templateResource($q, $http, umbRequestHelper) {
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.stylesheetResource#getAll
|
||||
* @methodOf umbraco.resources.stylesheetResource
|
||||
*
|
||||
* @description
|
||||
* Gets all registered stylesheets
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* stylesheetResource.getAll()
|
||||
* .then(function(stylesheets) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object containing the stylesheets.
|
||||
*
|
||||
*/
|
||||
getAll: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"GetAll")),
|
||||
'Failed to retrieve stylesheets ');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.stylesheetResource#getRulesByName
|
||||
* @methodOf umbraco.resources.stylesheetResource
|
||||
*
|
||||
* @description
|
||||
* Returns all defined child rules for a stylesheet with a given name
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* stylesheetResource.getRulesByName("ie7stylesheet")
|
||||
* .then(function(rules) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @returns {Promise} resourcePromise object containing the rules.
|
||||
*
|
||||
*/
|
||||
getById: function (id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"GetById",
|
||||
[{ id: id }])),
|
||||
'Failed to retreive template ');
|
||||
},
|
||||
|
||||
saveAndRender: function(html, templateId, pageId){
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"PostSaveAndRender"),
|
||||
{templateId: templateId, pageId: pageId, html: html }),
|
||||
'Failed to retreive template ');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('templateResource', templateResource);
|
||||
@@ -0,0 +1,14 @@
|
||||
angular.module('umbraco.services')
|
||||
.factory('gridService', function ($http, $q){
|
||||
|
||||
var configPath = "views/propertyeditors/grid/config/grid.editors.config.js";
|
||||
|
||||
var service = {
|
||||
getGridEditors: function () {
|
||||
return $http.get(configPath);
|
||||
}
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
});
|
||||
@@ -1,56 +1,585 @@
|
||||
// Gridview
|
||||
// -------------------------
|
||||
|
||||
.editor {
|
||||
border: 1px solid #cdcdcd;
|
||||
text-align: center;
|
||||
line-height: 100px;
|
||||
position: relative;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
-moz-transition: all 500ms ease-in-out;
|
||||
-ms-transition: all 500ms ease-in-out;
|
||||
-o-transition: all 500ms ease-in-out;
|
||||
transition: all 500ms ease-in-out;
|
||||
margin: 0 0 1.5% 0
|
||||
|
||||
|
||||
|
||||
// Sortabel
|
||||
// -------------------------
|
||||
.usky-grid .ui-sortable-helper {
|
||||
border: dashed 1px #000;
|
||||
background: #ccc;
|
||||
opacity: 0.4;
|
||||
height: 50px !important;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-helper *{
|
||||
border: none !important;
|
||||
background: none !important;
|
||||
color: #999 !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-helper .cell-tools{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder{
|
||||
border: 2px dashed @grayLight;
|
||||
padding: 20px;
|
||||
font-family: icomoon;
|
||||
text-align: center;
|
||||
font-size: 85px;
|
||||
line-height: 65px;
|
||||
color: @grayLighter;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder:hover{
|
||||
border-color: @gray;
|
||||
}
|
||||
|
||||
.usky-grid .ui-sortable-placeholder:before{
|
||||
content: "\e1bd";
|
||||
}
|
||||
|
||||
|
||||
|
||||
// utils
|
||||
// -------------------------
|
||||
.usky-grid-width {
|
||||
margin: 0 auto;
|
||||
width:100%;
|
||||
}
|
||||
.usky-grid .right {
|
||||
float:right;
|
||||
}
|
||||
|
||||
// general layout components
|
||||
// -------------------------
|
||||
.usky-grid .tb {
|
||||
display:table;
|
||||
width: 100%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
.usky-grid .td {
|
||||
display:table-cell;
|
||||
vertical-align:top;
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.0);
|
||||
}
|
||||
.usky-grid .tb:hover .td{
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.3);
|
||||
}
|
||||
.usky-grid .td.last {
|
||||
border-right:1px dashed rgba(182, 182, 182, 0.0) !important;
|
||||
}
|
||||
.usky-grid .tr {
|
||||
display:table-row;
|
||||
}
|
||||
.usky-grid .td2{
|
||||
width: 50%;
|
||||
}
|
||||
.usky-grid .td3{
|
||||
width: 33.33%;
|
||||
}
|
||||
.usky-grid .td4{
|
||||
width: 25%;
|
||||
}
|
||||
.usky-grid .td5{
|
||||
width: 20%;
|
||||
}
|
||||
.usky-grid .td6{
|
||||
width: 16.6%;
|
||||
}
|
||||
.usky-grid .middle {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.usky-grid .mainTb {
|
||||
border-collapse: separate;
|
||||
}
|
||||
.usky-grid .mainTd {
|
||||
position:relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// COLUMN
|
||||
// -------------------------
|
||||
.usky-grid .usky-column {
|
||||
|
||||
}
|
||||
.usky-grid .usky-column.last {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ROW
|
||||
// -------------------------
|
||||
.usky-grid .usky-row{
|
||||
position: relative;
|
||||
border: 1px dashed rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.editor:hover {
|
||||
border-color: #000
|
||||
|
||||
|
||||
|
||||
// CELL
|
||||
// -------------------------
|
||||
.usky-grid .usky-cell{
|
||||
position: relative;
|
||||
border: 1px dashed rgba(0,0,0,0);
|
||||
}
|
||||
|
||||
.editor:hover i {
|
||||
opacity: 1
|
||||
.usky-grid .cell-tools {
|
||||
transition: all .20s ease-in-out;
|
||||
-moz-transition: all .20s ease-in-out;
|
||||
-webkit-transition: all .20s ease-in-out;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.editor i {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
font-size: 20px;
|
||||
color: @white;
|
||||
background: @black;
|
||||
padding: 10px;
|
||||
-webkit-transition: all 500ms ease-in-out;
|
||||
-moz-transition: all 500ms ease-in-out;
|
||||
-ms-transition: all 500ms ease-in-out;
|
||||
-o-transition: all 500ms ease-in-out;
|
||||
transition: all 500ms ease-in-out;
|
||||
opacity: 0
|
||||
.usky-grid .cell-tools-add {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
bottom: -20px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 500;
|
||||
}
|
||||
|
||||
.editor i:hover {
|
||||
.usky-grid .cell-tools-add-single i{
|
||||
font-size: 85px;
|
||||
color: @grayLight;
|
||||
display: block;
|
||||
line-height: 55px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.editor i.icon-move {
|
||||
left: 0;
|
||||
cursor: move
|
||||
}
|
||||
.usky-grid .cell-tools-add-single a:hover i{color: @gray;}
|
||||
|
||||
.editor i.icon-edit {
|
||||
right: 36px;
|
||||
cursor: pointer
|
||||
.usky-grid .cell-tools-add-single a{text-decoration: none;}
|
||||
|
||||
.usky-grid .cell-tools-add-single p{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editor i.icon-trash {
|
||||
right: 0;
|
||||
cursor: pointer
|
||||
}
|
||||
.usky-grid .single-editor-rte p{
|
||||
display: block;
|
||||
}
|
||||
.usky-grid .single-editor-rte i, .usky-grid .single-editor-rte div{
|
||||
display: none;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-remove {
|
||||
display:inline-block;
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
text-align: right;
|
||||
z-index: 500;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-remove .iconBox:hover, .usky-grid .cell-tools-remove .iconBox:hover *{
|
||||
background: @red !important;
|
||||
border-color: @red !important;
|
||||
}
|
||||
|
||||
.usky-grid .cell-tools-move {
|
||||
display:inline-block;
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
right: -20px;
|
||||
z-index: 500;
|
||||
cursor: move
|
||||
}
|
||||
|
||||
|
||||
|
||||
// CONTROL
|
||||
// -------------------------
|
||||
.usky-grid .usky-control {
|
||||
transition: all .20s ease-in-out;
|
||||
-moz-transition: all .20s ease-in-out;
|
||||
-webkit-transition: all .20s ease-in-out;
|
||||
position:relative;
|
||||
display:block;
|
||||
|
||||
border: 1px dashed rgba(255, 0, 0, .0);
|
||||
border-bottom-width: 2px;
|
||||
|
||||
-webkit-background-clip: padding-box; /* for Safari */
|
||||
background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */
|
||||
}
|
||||
|
||||
.usky-grid .usky-control:hover{
|
||||
border-bottom:2px solid rgba(182, 182, 182, 0.3);
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-placeholder:hover{
|
||||
border-bottom:2px solid rgba(182, 182, 182, 0.0) !important;
|
||||
}
|
||||
|
||||
.usky-grid .removingControl{
|
||||
border: 1px dashed @red !important;
|
||||
}
|
||||
|
||||
.usky-grid .movingControl{
|
||||
border: 1px dashed @blue !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// CONTROL PLACEHOLDER
|
||||
// -------------------------
|
||||
.usky-grid .usky-control-placeholder {
|
||||
min-height: 100px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
text-align: -moz-center;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.usky-grid .usky-control-placeholder .placeholder{
|
||||
font-size: 14px; opacity: 0.7; text-align: left;
|
||||
padding: 5px;
|
||||
border:1px solid rgba(182, 182, 182, 0.3);
|
||||
height: 50px;
|
||||
}
|
||||
.usky-grid .usky-control-placeholder:hover .placeholder{
|
||||
border:1px solid rgba(182, 182, 182, 0.8);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// EDITOR PLACEHOLDER
|
||||
// -------------------------
|
||||
.usky-grid .usky-editor-placeholder{
|
||||
min-height: 65px;
|
||||
padding: 20px;
|
||||
padding-bottom: 30px;
|
||||
position: relative;
|
||||
background-color: white;
|
||||
border: 4px dashed @grayLight;
|
||||
text-align: center;
|
||||
text-align: -moz-center;
|
||||
}
|
||||
.usky-grid .usky-editor-placeholder i{
|
||||
color: @grayLight;
|
||||
font-size: 85px;
|
||||
line-height: 85px;
|
||||
display: block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Form elements
|
||||
// -------------------------
|
||||
.usky-grid textarea.textstring{
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
width: 99%;
|
||||
resize: none;
|
||||
color: @gray;
|
||||
}
|
||||
|
||||
.usky-grid .usky-cell-rte textarea{
|
||||
display: none !important
|
||||
}
|
||||
|
||||
.usky-grid .usky-cell-media .caption{
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
background: #fff;
|
||||
outline: none;
|
||||
width: 99%;
|
||||
resize: none;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.usky-grid .cellPanelRte {
|
||||
min-height:60px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ICONS
|
||||
// -------------------------
|
||||
.usky-grid .iconBox {
|
||||
padding: 4px 7px 4px 7px;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
border-radius: 200px;
|
||||
background: rgba(255,255,255, 1);
|
||||
border:1px solid rgb(182, 182, 182);
|
||||
margin: 2px;
|
||||
}
|
||||
.usky-grid .iconBox:hover, .usky-grid .iconBox:hover *{
|
||||
background: @blue !important;
|
||||
color: white !important;
|
||||
border-color: @blue !important;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox a:hover {
|
||||
text-decoration:none;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox.selected {
|
||||
-webkit-appearance: none;
|
||||
background-image: -moz-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: -webkit-gradient(linear,0 0,0 100%,from(#e6e6e6),to(#bfbfbf));
|
||||
background-image: -webkit-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: -o-linear-gradient(top,#e6e6e6,#bfbfbf);
|
||||
background-image: linear-gradient(to bottom,#e6e6e6,#bfbfbf);
|
||||
background-repeat: repeat-x;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe6e6e6',endColorstr='#ffbfbfbf',GradientType=0);
|
||||
zoom: 1;
|
||||
border-color: #bfbfbf #bfbfbf #999;
|
||||
border-color: rgba(0,0,0,0.1) rgba(0,0,0,0.1) rgba(0,0,0,0.25);
|
||||
-webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
-moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.15),0 1px 2px rgba(0,0,0,0.05);
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.usky-grid .iconBox i {
|
||||
font-size:16px !important;
|
||||
color: #5F5F5F;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
.usky-grid ul {
|
||||
display:inline-block;
|
||||
list-style:none;
|
||||
padding:0;
|
||||
margin: 10px 0 0 0;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
.usky-grid .help-text {
|
||||
background: @grayLighter;
|
||||
color: @gray;
|
||||
font-size: 14px;
|
||||
padding: 10px 20px 10px 20px;
|
||||
border-radius: 15px;
|
||||
display: inline-block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.usky-grid ul li {
|
||||
display: inline-block;
|
||||
width: 120px;
|
||||
margin: 8px 8px 0px 8px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// TINYMCE EDITOR
|
||||
// -------------------------
|
||||
.usky-grid .mce-panel {
|
||||
border:none !important;
|
||||
clear:both;
|
||||
}
|
||||
|
||||
.usky-grid .mce-btn button {
|
||||
padding: 8px 6px;
|
||||
line-height: inherit;
|
||||
}
|
||||
|
||||
.usky-grid .mce-toolbar {
|
||||
border: 1px solid rgba(207, 207, 207, 0.7);
|
||||
background-color: rgba(250, 250, 250, 1);
|
||||
z-index: 100;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
padding: -1px;
|
||||
position: absolute;
|
||||
margin: -1px -1px 0 -1px;
|
||||
-webkit-box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
-moz-box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
box-shadow: 2px 2px 10px 0px rgba(50, 50, 50, 0.14);
|
||||
z-index: 9999999;
|
||||
}
|
||||
|
||||
.mce-flow-layout-item {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.usky-grid .mce-panel {
|
||||
background: transparent !important;
|
||||
}
|
||||
.usky-grid .mce-floatpanel {
|
||||
background-color: #F7F7F7 !important;
|
||||
}
|
||||
|
||||
|
||||
// MEDIA EDITOR
|
||||
// -------------------------
|
||||
.usky-grid .fullSizeImage {
|
||||
width:100%
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* Width */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .boxWidth {
|
||||
text-align:right;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.usky-grid .boxWidth input {
|
||||
text-align: center;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
.usky-grid .boxWidth label {
|
||||
font-size: 10px;
|
||||
padding: 0;
|
||||
margin: 5px 5px 0 0;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* Margin control */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .usky-cell{
|
||||
|
||||
}
|
||||
|
||||
.usky-grid .usky-row{
|
||||
|
||||
}
|
||||
|
||||
.usky-grid .usky-control{
|
||||
margin: 30px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.usky-grid .usky-templates-columns{
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* template */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .uSky-templates {
|
||||
text-align:center;
|
||||
overflow:hidden;
|
||||
width:100%;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template {
|
||||
display:inline-block;
|
||||
width:100px;
|
||||
padding-right: 30px;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb:hover {
|
||||
border:5px solid @blue;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb {
|
||||
width:100%;
|
||||
height:150px;
|
||||
padding:10px;
|
||||
background-color: @grayLighter;
|
||||
border: 5px solid @grayLight;
|
||||
cursor:pointer;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tr {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb .uSky-templates-column {
|
||||
height:100%;
|
||||
border: 1px dashed @grayLight;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.usky-grid .uSky-templates-template .tb .uSky-templates-column.last {
|
||||
border-right: 1px dashed @grayLight !important;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************************************/
|
||||
/* template column */
|
||||
/**************************************************************************************************/
|
||||
|
||||
.usky-grid .usky-templates-columns .td{
|
||||
border: none !important;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.usky-grid .usky-templates-columns .td i{
|
||||
color: @gray;
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
|
||||
.usky-grid .mainTbpt:hover {
|
||||
border-color:@blue;
|
||||
}
|
||||
|
||||
.usky-grid .mainTbpt {
|
||||
cursor:pointer;
|
||||
border-spacing: 5px;
|
||||
border-collapse: separate;
|
||||
height: 35px;
|
||||
border: 2px solid @grayLight;
|
||||
margin:0px;
|
||||
background-color: @grayLighter;
|
||||
}
|
||||
.usky-grid .mainTdpt {
|
||||
height: 35px;
|
||||
border: 1px dashed @grayLight;
|
||||
margin:0px;
|
||||
background-color: rgba(228, 228, 228, 0.41);
|
||||
}
|
||||
@@ -6,6 +6,8 @@
|
||||
/*wft ms?*/
|
||||
*{ -ms-touch-action: none;}
|
||||
|
||||
.ace_editor { height: 200px; }
|
||||
|
||||
.nounderline {text-decoration: none !important}
|
||||
.nounderline:hover {text-decoration: underline !important}
|
||||
.nounderline * {text-decoration: none !important; border: none}
|
||||
|
||||
@@ -0,0 +1,784 @@
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #EEEEEE;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
body.open {
|
||||
padding-left:275px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-left: 10px;
|
||||
font-size: 14px;
|
||||
color: #d9d9d9;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuning #TuningBg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
width: 275px;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin-left: -275px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 16px;
|
||||
background: #1D1D1D;
|
||||
-webkit-box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
-moz-box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
box-shadow: 0 0 14px rgba(0, 0, 0, 0);
|
||||
-webkit-transition: all 0.2s ease-in-out;
|
||||
-moz-transition: all 0.2s ease-in-out;
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.show {
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
.wait {
|
||||
margin: 10px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning .tuning-wrapper {
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.tuning .wrapper-pading {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.tuning #TuningBg.open {
|
||||
margin-left: 0;
|
||||
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.tuning .colpick {
|
||||
z-index: 99999999;
|
||||
}
|
||||
|
||||
.tuning .nav {
|
||||
padding: 0 10px;
|
||||
margin-top: 12px;
|
||||
margin-bottom: 30px;
|
||||
text-transform: uppercase;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
color: #d9d9d9 !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none;
|
||||
border-bottom: 3px solid transparent;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li.active > a,
|
||||
.tuning .nav-tabs > li.active > a:hover,
|
||||
.tuning .nav-tabs > li.active > a:focus {
|
||||
color: #d9d9d9;
|
||||
cursor: default;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none;
|
||||
border-bottom: 3px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a:hover {
|
||||
color: #d9d9d9 !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none !important;
|
||||
border-bottom: 3px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .nav > li > a:hover,
|
||||
.tuning .nav > li > a:focus {
|
||||
color: #d9d9d9 !important;
|
||||
text-decoration: none !important;
|
||||
background-color: #1D1D1D !important;
|
||||
border: none !important;
|
||||
border-bottom: 3px solid #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
border-bottom: 3px solid transparent;
|
||||
/*border-radius: 2px 2px 0 0;*/
|
||||
|
||||
}
|
||||
|
||||
.nav-tabs > li {
|
||||
float: left;
|
||||
margin-top: 1px;
|
||||
margin-bottom: -1px;
|
||||
}
|
||||
|
||||
.tuning .nav-tabs > li > a {
|
||||
color: #ffffff;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .nav > li > a {
|
||||
padding: 5px 7px;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a span {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* .panel-heading */
|
||||
|
||||
.tab-pane {
|
||||
border-bottom: 1px solid #343434;
|
||||
}
|
||||
|
||||
.tuning .panel-heading {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading {
|
||||
color: #d9d9d9;
|
||||
background-color: #1D1D1D;
|
||||
border-left: 4px transparent solid;
|
||||
border-color: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading:hover,
|
||||
.tuning .panel-default.selected > .panel-heading {
|
||||
color: #d9d9d9;
|
||||
text-decoration: none;
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
.tuning .panel-title > a {
|
||||
display: block;
|
||||
padding: 5px 0 5px 17px;
|
||||
font-size: 13px;
|
||||
line-height: 22px;
|
||||
color: #d9d9d9;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .panel-default > .panel-heading h4 {
|
||||
margin: 0 0 0 -4px;
|
||||
border-top: 1px solid #343434;
|
||||
}
|
||||
|
||||
.panel-group .panel + .panel {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected {
|
||||
margin: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected > .panel-heading h4 {
|
||||
margin: 0 0 0 0;
|
||||
color: #d9d9d9;
|
||||
border-top: none;
|
||||
border-bottom: 1px solid #6D6D6D;
|
||||
}
|
||||
|
||||
.tuning .panel-default.selected > .panel-heading h4 a {
|
||||
padding: 5px 0 5px 13px;
|
||||
}
|
||||
|
||||
/* panel */
|
||||
|
||||
.tuning .panel-default {
|
||||
background-color: #1D1D1D;
|
||||
border: 0 solid rgba(217, 217, 217, 0.5);
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.tuning .panel-group .panel {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.panel-collapse {
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
}
|
||||
|
||||
.tuning .btn-default-save,
|
||||
.tuning .btn-default-save:focus {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
color: #fff;
|
||||
background-color: #53a93f;
|
||||
border-color: #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.tuning .btn-default-save:hover {
|
||||
color: #fff;
|
||||
background-color: rgba(83, 169, 63, 0.81);
|
||||
}
|
||||
|
||||
.tuning .btn-default-delete,
|
||||
.tuning .btn-default-delete:focus {
|
||||
float: right;
|
||||
margin-top: 20px;
|
||||
margin-right: 10px;
|
||||
color: #343434;
|
||||
background: #e4e4e4;
|
||||
border-color: #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.tuning .btn-default-delete:hover {
|
||||
color: #343434;
|
||||
background-color: rgba(228, 228, 228, 0.65);
|
||||
}
|
||||
|
||||
.tuning .field-title {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .div-field {
|
||||
margin-bottom: 10px;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tuning .sp-replacer {
|
||||
float: left;
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
background: none;
|
||||
border: solid 1px #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .panel-body {
|
||||
border-top: none !important;
|
||||
}
|
||||
|
||||
.tuning select {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.tuning .sp-dd {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tuning .sp-preview {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
margin-right: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tuning .box-slider {
|
||||
padding: 7px 2px 12px 2px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.tuning .ui-widget-content {
|
||||
background: rgba(255, 255, 255, 0.09) !important;
|
||||
border: 0px solid #fff !important;
|
||||
border-radius: 2px !important;
|
||||
}
|
||||
|
||||
.tuning .ui-slider-horizontal {
|
||||
float: left;
|
||||
width: 155px;
|
||||
height: .3em !important;
|
||||
}
|
||||
|
||||
.tuning .ui-slider .ui-slider-handle {
|
||||
top: -0.3em;
|
||||
width: 0.3em !important;
|
||||
height: 0.9em !important;
|
||||
margin-left: 0;
|
||||
color: #d9d9d9 !important;
|
||||
cursor: pointer;
|
||||
border-top-right-radius: 1px;
|
||||
border-bottom-right-radius: 1px;
|
||||
border-bottom-left-radius: 1px;
|
||||
border-top-left-radius: 1px;
|
||||
}
|
||||
|
||||
.tuning .ui-slider .ui-slider-handle:hover,
|
||||
.tuning .ui-slider .ui-slider-handle:focus {
|
||||
color: #d9d9d9 !important;
|
||||
}
|
||||
|
||||
.tuning .slider-input {
|
||||
float: right;
|
||||
width: 25px;
|
||||
padding: 0;
|
||||
margin-top: -9px;
|
||||
margin-right: 1px;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
text-align: right;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.tuning .slider-span {
|
||||
float: right;
|
||||
margin: -9px 0 0 0;
|
||||
font-size: 11px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
@-moz-document url-prefix() {
|
||||
.tuning .slider-input {
|
||||
margin-top: -6px;
|
||||
}
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreviewContainer {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview {
|
||||
float: left;
|
||||
width: 50px;
|
||||
height: 30px;
|
||||
clear: both;
|
||||
color: rgba(217, 217, 217, 0.5);
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
border: 1px solid rgba(217, 217, 217, 0.5);
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview:hover {
|
||||
color: #d9d9d9;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .imagePickerPreview i {
|
||||
font-size: 14px;
|
||||
line-height: 30px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .colorPickerDelete {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
margin-left: 3px;
|
||||
font-size: 10px;
|
||||
color: rgba(217, 217, 217, 0.5);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tuning .colorPickerDelete:hover {
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning .tuning-tools {
|
||||
position: absolute;
|
||||
right: -28px;
|
||||
margin: 25px 0 0 0;
|
||||
}
|
||||
|
||||
.tuning #TuningBg.open .tuning-tools {
|
||||
right: -33px;
|
||||
}
|
||||
|
||||
.tuning .tuning-tools div {
|
||||
display: block;
|
||||
padding: 8px 8px 8px 9px;
|
||||
margin: 5px 0 0 0;
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
background: #353535;
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
-webkit-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
-moz-box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: 0 0 8px rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
.tuning .tuning-tools div:hover,
|
||||
.tuning .tuning-tools div.selected {
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
background: #1D1D1D;
|
||||
}
|
||||
|
||||
/* image picker */
|
||||
|
||||
.tuningImagePicker {
|
||||
height: 500px;
|
||||
padding: 0;
|
||||
margin-top: 10px;
|
||||
overflow: auto;
|
||||
text-align: left;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuningImagePicker ul {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-left: 17px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuningImagePicker li {
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.tuningImagePicker ul.media-items li {
|
||||
margin-right: 17px;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 110px;
|
||||
height: 60px;
|
||||
cursor: pointer;
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
border: 2px solid #F3F2F2;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview .folder {
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
font-size: 40px;
|
||||
color: gainsboro;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview .folder-name {
|
||||
margin-top: -5px;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
line-height: 0;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.tuningImagePicker .media-preview:hover,
|
||||
.media-preview.selected {
|
||||
border: 2px solid #84B8F0;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker {
|
||||
padding: 10px 20px 0 15px;
|
||||
}
|
||||
|
||||
.tuningImagePicker .modal-dialog {
|
||||
width: 618px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 10px;
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb > li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb > li a {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb input {
|
||||
padding: 0;
|
||||
margin: -4px -4px;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .fileinput-button {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
font-size: 19px;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker input.input-media {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
margin: 0;
|
||||
font-size: 23px;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
filter: alpha(opacity=0);
|
||||
transform: translate(-300px, 0) scale(4);
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.bodyTuningImagePicker .breadcrumb a.disabled,
|
||||
.bodyTuningImagePicker .breadcrumb a.disabled:hover {
|
||||
color: grey;
|
||||
text-decoration: none;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.tuningImagePicker h3 {
|
||||
font-size: 18px;
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
/* font picker */
|
||||
|
||||
.tuning-fontfamilypicker .show {
|
||||
margin-top: 10px;
|
||||
font-size: 32px;
|
||||
line-height: 34px;
|
||||
color: #242424;
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview {
|
||||
float: left;
|
||||
width: 90%;
|
||||
min-height: 50px;
|
||||
padding: 8px;
|
||||
margin-top: 4px;
|
||||
clear: both;
|
||||
font-size: 18px;
|
||||
color: rgba(255, 255, 255, 0.8);
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.28);
|
||||
border: 1px solid rgba(217, 217, 217, 0.5);
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview span {
|
||||
font-size: 32px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
.tuning .fontFamilyPickerPreview:hover {
|
||||
color: #d9d9d9;
|
||||
border: 1px solid #d9d9d9;
|
||||
}
|
||||
|
||||
.tuning-fontfamilypicker {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
}
|
||||
|
||||
.tuning .palette {
|
||||
padding: 0;
|
||||
margin: 20px 0 20px 20px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.tuning .palette li {
|
||||
margin: 10px 0 0 0;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
cursor: pointer;
|
||||
background-color: rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.tuning .palette div {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
border: 1px solid rgba(255, 255, 255, 0.61);
|
||||
}
|
||||
|
||||
.tuning .palette li:hover {
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
.tuning .palette li:hover div {
|
||||
border: 1px solid #ffffff;
|
||||
}
|
||||
|
||||
.tuning .palette li:hover p {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.tuning .palette div span {
|
||||
display: table-cell;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
padding: 0 0 0 0;
|
||||
margin: 0;
|
||||
border: 1px solid rgba(0, 0, 0, 0.55);
|
||||
}
|
||||
|
||||
.tuning .palette p {
|
||||
float: left;
|
||||
margin: 7px 0 0 10px;
|
||||
color: rgba(255, 255, 255, 0.57);
|
||||
}
|
||||
|
||||
/******* IFRAME *******/
|
||||
|
||||
.desktop {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0 auto;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.laptop {
|
||||
width: 1366px;
|
||||
height: 768px;
|
||||
}
|
||||
|
||||
.iPad-portrait {
|
||||
width: 769px;
|
||||
height: 929px;
|
||||
}
|
||||
|
||||
.iPad-landscape {
|
||||
width: 1024px;
|
||||
height: 675px;
|
||||
}
|
||||
|
||||
.smartphone-portrait {
|
||||
width: 320px;
|
||||
height: 504px;
|
||||
}
|
||||
|
||||
.smartphone-landscape {
|
||||
width: 480px;
|
||||
height: 256px;
|
||||
}
|
||||
|
||||
.border {
|
||||
margin: 75px auto;
|
||||
background-color: #ffffff;
|
||||
border-radius: 10px;
|
||||
opacity: 1.0;
|
||||
box-shadow: 0 0 0 29px #fff, 0 0 0 30px #dee0e3;
|
||||
transition: all 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
iframe {
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow-x: hidden;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.flip:before {
|
||||
-webkit-transform: rotate(90deg);
|
||||
-moz-transform: rotate(90deg);
|
||||
-o-transform: rotate(90deg);
|
||||
}
|
||||
|
||||
/******* preview-device *******/
|
||||
|
||||
ul.preview-device {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
border-top: 1px solid #343434;
|
||||
}
|
||||
|
||||
ul.preview-device li {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
clear: both;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-left: 4px solid transparent;
|
||||
-webkit-transition: all .3s linear;
|
||||
-moz-transition: all .3s linear;
|
||||
transition: all .3s linear;
|
||||
}
|
||||
|
||||
ul.preview-device li div {
|
||||
padding: 10px;
|
||||
border-bottom: 1px solid #343434;
|
||||
}
|
||||
|
||||
ul.preview-device li:hover,
|
||||
ul.preview-device li.selected {
|
||||
background-color: rgba(255, 255, 255, 0.09);
|
||||
border-left: 4px #f57020 solid;
|
||||
}
|
||||
|
||||
ul.preview-device li i {
|
||||
font-size: 80px;
|
||||
line-height: 80px;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
ul.preview-device li span {
|
||||
display: block;
|
||||
color: #d9d9d9;
|
||||
}
|
||||
|
||||
/******* font-face *******/
|
||||
|
||||
#speechbubble {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 40px;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
display: none;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
margin-left: 300px;
|
||||
text-align: left;
|
||||
background: none;
|
||||
border: none;
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
#speechbubble p {
|
||||
position: relative;
|
||||
padding: 8px 30px 8px 20px;
|
||||
margin: auto;
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
color: #ffffff;
|
||||
text-shadow: none;
|
||||
background-color: #46a546;
|
||||
border: none;
|
||||
border-color: transparent;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/******* font-face *******/
|
||||
|
||||
@font-face {
|
||||
src: url('/Umbraco/assets/fonts/helveticons/helveticons.eot') !important;
|
||||
src: url('/Umbraco/assets/fonts/helveticons/helveticons.eot?#iefix') format('embedded-opentype'), url('/Umbraco/assets/fonts/helveticons/helveticons.ttf') format('truetype'), url('/Umbraco/assets/fonts/helveticons/helveticons.svg#icomoon') format('svg') !important;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
LazyLoad.js([
|
||||
'/Umbraco/lib/jquery/jquery-2.0.3.min.js',
|
||||
'/Umbraco/lib/jquery/jquery-ui-1.10.4.custom.min.js',
|
||||
'/Umbraco/lib/angular/1.1.5/angular.min.js',
|
||||
'/Umbraco/lib/underscore/underscore.js',
|
||||
'/Umbraco/js/app.js',
|
||||
'/Umbraco/js/umbraco.resources.js',
|
||||
'/Umbraco/js/umbraco.services.js',
|
||||
'/Umbraco/js/umbraco.security.js',
|
||||
'/Umbraco/ServerVariables',
|
||||
'/Umbraco/lib/angular-bootstrap/ui-bootstrap-tpls-0.10.0.min.js',
|
||||
'/Umbraco/lib/spectrum/spectrum.js',
|
||||
'http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
|
||||
'/Umbraco/js/tuning.config.js',
|
||||
'/Umbraco/js/tuning.palettes.js',
|
||||
'/umbraco/js/tuning.panel.js'
|
||||
], function () {
|
||||
jQuery(document).ready(function () {
|
||||
angular.bootstrap(document, ['umbraco.tuning']);
|
||||
});
|
||||
}
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -0,0 +1,238 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="/Umbraco/lib/bootstrap/css/bootstrap.min.3.0.1.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/assets/css/tuning.panelStyles.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/spectrum/spectrum.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/jquery/jquery-ui-1.10.4.custom.min.css" type="text/css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body id="tuningPanel" ng-class="{open:isOpen}" ng-controller="Umbraco.tuningController">
|
||||
|
||||
<div class="wait" ng-show="!frameLoaded">Loading ...</div>
|
||||
|
||||
<div id="demo-iframe-wrapper" ng-show="frameLoaded" class="{{previewDevice.css}}">
|
||||
<iframe id="resultFrame" ng-src="{{pageId}}" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<div class="tuning">
|
||||
|
||||
<div id="TuningBg" ng-class="{open:isOpen}" style="display: block;">
|
||||
|
||||
<div class="tuning-tools">
|
||||
|
||||
<div ng-click="togglePanel()">
|
||||
<i ng-if="isOpen" class="icon icon-left-double-arrow"></i>
|
||||
<i ng-if="!isOpen" class="icon icon-right-double-arrow"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('previewDevice')" ng-class="{selected:settingIsOpen=='previewDevice', show:frameLoaded}" style="display:none">
|
||||
<i class="icon icon-display"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('setting')" ng-class="{selected:settingIsOpen=='setting', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-paint-roller"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('presetColors')" ng-class="{selected:settingIsOpen=='presetColors', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-palette"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tuning-wrapper">
|
||||
|
||||
<div ng-show="settingIsOpen == 'previewDevice'">
|
||||
|
||||
<h2>DEVICES</h2>
|
||||
<ul class="preview-device">
|
||||
<li ng-repeat="device in devices" ng-class=" { selected:previewDevice==device }" ng-click="updatePreviewDevice(device)">
|
||||
<div><i class="icon {{device.icon}}"></i><span>{{device.name}}</span></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'setting'">
|
||||
|
||||
<tabset vertical="false">
|
||||
|
||||
<tab ng-repeat="category in tuningModel.categories" active="category.active">
|
||||
|
||||
<tab-heading>
|
||||
<span>{{category.name}}</span>
|
||||
</tab-heading>
|
||||
|
||||
<div ng-repeat="section in category.sections">
|
||||
|
||||
<accordion close-others="true">
|
||||
|
||||
<accordion-group ng-repeat="subSection in section.subSections"
|
||||
ng-class="{true:'selected', false:''}[isOpen]"
|
||||
is-open="(schemaFocus != '' && schemaFocus == subSection.name.toLowerCase())">
|
||||
|
||||
<accordion-heading>
|
||||
<span ng-click="accordionOpened(subSection.name)" ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
{{subSection.name}}
|
||||
</span>
|
||||
</accordion-heading>
|
||||
|
||||
<div ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
<div class="div-field" ng-repeat="field in subSection.fields">
|
||||
|
||||
<span class="field-title">{{field.name}}:</span>
|
||||
|
||||
<div ng-if="field.type == 'colorPicker'">
|
||||
<spectrum colorselected="field.value"></spectrum>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgImagePicker'" class="imagePickerPreviewContainer">
|
||||
<div class="imagePickerPreview" ng-click="open(field)" style="background-image:{{ field.value }}">
|
||||
<i class="icon icon-add"></i>
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgPositionPicker'">
|
||||
<select ng-options="BackgroundPosition for BackgroundPosition in BackgroundPositions" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgRepeatPicker'">
|
||||
<select ng-options="BackgroundRepeat for BackgroundRepeat in BackgroundRepeats" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgAttachmentPicker'">
|
||||
<select ng-options="BackgroundAttachment for BackgroundAttachment in BackgroundAttachments" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'layoutPicker'">
|
||||
<select ng-options="Layout for Layout in Layouts" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div class="box-slider" ng-if="field.type == 'slider'">
|
||||
<div ui-slider min="{{field.min}}" max="{{field.max}}" step="1" ng-model="field.value"></div>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'checkbox'">
|
||||
<input type="checkbox" ng-checked="field.value == 'true'" ng-model="field.value">
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'displayPicker'">
|
||||
<select ng-options="display for display in displays" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'optionHomePicker'">
|
||||
<select ng-options="optionHome for optionHome in optionHomes" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'fontFamilyPicker'">
|
||||
<div class="fontFamilyPickerPreview" ng-click="openFontFamilyPickerModal(field)" style="font-family:{{ field.value }}">
|
||||
<span>Aa</span>
|
||||
{{ field.value }}
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="fa fa-times colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</accordion-group>
|
||||
</accordion>
|
||||
|
||||
</div>
|
||||
|
||||
</tab>
|
||||
|
||||
</tabset>
|
||||
|
||||
<button class="btn btn-default btn-default-save" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-delete" ng-click="deleteTuning()">reset</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'presetColors'">
|
||||
|
||||
<h2>PALETTE COLORS</h2>
|
||||
<ul class="palette">
|
||||
<li ng-click="refreshtuningByPalette(palette)" ng-repeat="palette in tuningPalette">
|
||||
<div>
|
||||
<span style="background-color: {{ palette.mainColor }}"></span>
|
||||
</div>
|
||||
<p>{{ palette.name }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-default btn-default-save" style="display:none" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-save" ng-click="makePreset()">make it !</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="myModalContent.html">
|
||||
<div class="modal-header bodyTuningImagePicker ng-scope">
|
||||
<ul class="breadcrumb">
|
||||
<li ng-if="startNodeId == -1">
|
||||
<a href="" ng-click="gotoFolder()">Media</a>
|
||||
</li>
|
||||
|
||||
<!-- ngRepeat: item in path -->
|
||||
<li ng-repeat="item in currentPath" class="ng-scope">
|
||||
<a ng-if="currentFolder.id == item.id" href="" ng-class="{disabled:currentFolder.id == item.id}">{{ item.name }}</a>
|
||||
<a ng-if="currentFolder.id != item.id" ng-click="gotoFolder(item)">{{ item.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-body bodyTuningImagePicker">
|
||||
<ul class="tuningImagePicker">
|
||||
<li>
|
||||
<ul class="media-items">
|
||||
<li ng-repeat="child in currentFolder.children | orderBy:'isFolder':true">
|
||||
<div ng-if="!child.isFolder" class=" media-preview" ng-class="{selected:selectedMedia.id == child.id}" ng-click="selectMedia(child)" style="background-image: url({{ child.thumbnail }})"></div>
|
||||
<div ng-if="child.isFolder" class=" media-preview" ng-click="selectMedia(child)">
|
||||
<i class="icon icon-folder folder"><p class="folder-name">{{child.name}}</p></i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="fontFamilyPickerModel.html">
|
||||
|
||||
<div class="modal-header tuning-fontfamilypicker">
|
||||
<select ng-model="selectedFont" ng-change="showFontPreview(selectedFont)" ng-options="font as font.fontFamily group by font.fontType for font in fonts"></select>
|
||||
<select ng-model="selectedFont.variant" ng-change="showFontPreview(selectedFont)" ng-options="variant for variant in selectedFont.variants" />
|
||||
</div>
|
||||
|
||||
<div class="modal-body tuning-fontfamilypicker">
|
||||
<span class="show" ng-style="setStyleVariant()">Aa Bb Cc 1 2 3 4… <br />The quick brown fox jumps over the lazy dog…</span>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer tuning-fontfamilypicker">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="speechbubble">
|
||||
<p>Styles saved and visible at the website</p>
|
||||
</div>
|
||||
|
||||
<script src="/umbraco/lib/lazyload/lazyload.min.js"></script>
|
||||
<script src="/umbraco/js/tuning.loader.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,148 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* jQuery UI Slider plugin wrapper */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
angular.module('ui.slider', []).value('uiSliderConfig', {}).directive('uiSlider', ['uiSliderConfig', '$timeout', function (uiSliderConfig, $timeout) {
|
||||
uiSliderConfig = uiSliderConfig || {};
|
||||
return {
|
||||
require: 'ngModel',
|
||||
template: '<div><div class="slider" /><span class="slider-span">px</span><input class="slider-input" ng-model="value"></div>',
|
||||
replace: true,
|
||||
compile: function () {
|
||||
return function (scope, elm, attrs, ngModel) {
|
||||
|
||||
scope.value = ngModel.$viewValue;
|
||||
|
||||
function parseNumber(n, decimals) {
|
||||
return (decimals) ? parseFloat(n) : parseInt(n);
|
||||
};
|
||||
|
||||
var options = angular.extend(scope.$eval(attrs.uiSlider) || {}, uiSliderConfig);
|
||||
// Object holding range values
|
||||
var prevRangeValues = {
|
||||
min: null,
|
||||
max: null
|
||||
};
|
||||
|
||||
// convenience properties
|
||||
var properties = ['min', 'max', 'step'];
|
||||
var useDecimals = (!angular.isUndefined(attrs.useDecimals)) ? true : false;
|
||||
|
||||
var init = function () {
|
||||
// When ngModel is assigned an array of values then range is expected to be true.
|
||||
// Warn user and change range to true else an error occurs when trying to drag handle
|
||||
if (angular.isArray(ngModel.$viewValue) && options.range !== true) {
|
||||
console.warn('Change your range option of ui-slider. When assigning ngModel an array of values then the range option should be set to true.');
|
||||
options.range = true;
|
||||
}
|
||||
|
||||
// Ensure the convenience properties are passed as options if they're defined
|
||||
// This avoids init ordering issues where the slider's initial state (eg handle
|
||||
// position) is calculated using widget defaults
|
||||
// Note the properties take precedence over any duplicates in options
|
||||
angular.forEach(properties, function (property) {
|
||||
if (angular.isDefined(attrs[property])) {
|
||||
options[property] = parseNumber(attrs[property], useDecimals);
|
||||
}
|
||||
});
|
||||
|
||||
elm.find(".slider").slider(options);
|
||||
init = angular.noop;
|
||||
};
|
||||
|
||||
// Find out if decimals are to be used for slider
|
||||
angular.forEach(properties, function (property) {
|
||||
// support {{}} and watch for updates
|
||||
attrs.$observe(property, function (newVal) {
|
||||
if (!!newVal) {
|
||||
init();
|
||||
elm.find(".slider").slider('option', property, parseNumber(newVal, useDecimals));
|
||||
}
|
||||
});
|
||||
});
|
||||
attrs.$observe('disabled', function (newVal) {
|
||||
init();
|
||||
elm.find(".slider").slider('option', 'disabled', !!newVal);
|
||||
});
|
||||
|
||||
// Watch ui-slider (byVal) for changes and update
|
||||
scope.$watch(attrs.uiSlider, function (newVal) {
|
||||
init();
|
||||
if (newVal != undefined) {
|
||||
elm.find(".slider").slider('option', newVal);
|
||||
}
|
||||
}, true);
|
||||
|
||||
// Late-bind to prevent compiler clobbering
|
||||
$timeout(init, 0, true);
|
||||
|
||||
// Update model value from slider
|
||||
elm.find(".slider").bind('slidestop', function (event, ui) {
|
||||
ngModel.$setViewValue(ui.values || ui.value);
|
||||
scope.$apply();
|
||||
});
|
||||
|
||||
elm.bind('slide', function (event, ui) {
|
||||
event.stopPropagation();
|
||||
elm.find(".slider-input").val(ui.value);
|
||||
});
|
||||
|
||||
// Update slider from model value
|
||||
ngModel.$render = function () {
|
||||
init();
|
||||
var method = options.range === true ? 'values' : 'value';
|
||||
|
||||
if (isNaN(ngModel.$viewValue) && !(ngModel.$viewValue instanceof Array))
|
||||
ngModel.$viewValue = 0;
|
||||
|
||||
scope.value = ngModel.$viewValue;
|
||||
|
||||
// Do some sanity check of range values
|
||||
if (options.range === true) {
|
||||
|
||||
// Check outer bounds for min and max values
|
||||
if (angular.isDefined(options.min) && options.min > ngModel.$viewValue[0]) {
|
||||
ngModel.$viewValue[0] = options.min;
|
||||
}
|
||||
if (angular.isDefined(options.max) && options.max < ngModel.$viewValue[1]) {
|
||||
ngModel.$viewValue[1] = options.max;
|
||||
}
|
||||
|
||||
// Check min and max range values
|
||||
if (ngModel.$viewValue[0] >= ngModel.$viewValue[1]) {
|
||||
// Min value should be less to equal to max value
|
||||
if (prevRangeValues.min >= ngModel.$viewValue[1])
|
||||
ngModel.$viewValue[0] = prevRangeValues.min;
|
||||
// Max value should be less to equal to min value
|
||||
if (prevRangeValues.max <= ngModel.$viewValue[0])
|
||||
ngModel.$viewValue[1] = prevRangeValues.max;
|
||||
}
|
||||
|
||||
// Store values for later user
|
||||
prevRangeValues.min = ngModel.$viewValue[0];
|
||||
prevRangeValues.max = ngModel.$viewValue[1];
|
||||
|
||||
}
|
||||
elm.find(".slider").slider(method, ngModel.$viewValue);
|
||||
};
|
||||
|
||||
scope.$watch("value", function () {
|
||||
ngModel.$setViewValue(scope.value);
|
||||
}, true);
|
||||
|
||||
scope.$watch(attrs.ngModel, function () {
|
||||
if (options.range === true) {
|
||||
ngModel.$render();
|
||||
}
|
||||
}, true);
|
||||
|
||||
function destroy() {
|
||||
elm.find(".slider").slider('destroy');
|
||||
}
|
||||
elm.find(".slider").bind('$destroy', destroy);
|
||||
};
|
||||
}
|
||||
};
|
||||
}]);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* spectrum color picker directive */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
angular.module('spectrumcolorpicker', [])
|
||||
.directive('spectrum', function () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
scope: {
|
||||
colorselected: '='
|
||||
},
|
||||
link: function (scope, $element) {
|
||||
|
||||
var initColor;
|
||||
|
||||
$element.find("input").spectrum({
|
||||
color: scope.colorselected,
|
||||
preferredFormat: "rgb",
|
||||
showAlpha: true,
|
||||
showInput: true,
|
||||
change: function (color) {
|
||||
scope.colorselected = color.toRgbString();
|
||||
scope.$apply();
|
||||
},
|
||||
move: function (color) {
|
||||
scope.colorselected = color.toRgbString();
|
||||
scope.$apply();
|
||||
},
|
||||
beforeShow: function (color) {
|
||||
initColor = angular.copy(scope.colorselected);
|
||||
$(this).spectrum("container").find(".sp-cancel").click(function (e) {
|
||||
scope.colorselected = initColor;
|
||||
scope.$apply();
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
scope.$watch('colorselected', function () {
|
||||
$element.find("input").spectrum("set", scope.colorselected);
|
||||
}, true);
|
||||
|
||||
},
|
||||
template:
|
||||
'<div><input type=\'text\' ng-model=\'colorselected\' /></div>',
|
||||
replace: true
|
||||
};
|
||||
})
|
||||
@@ -0,0 +1,758 @@
|
||||
/*********************************************************************************************************/
|
||||
/* tuning panel app and controller */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
// tuning main app
|
||||
angular.module("umbraco.tuning", ['ui.bootstrap', 'spectrumcolorpicker', 'ui.slider', 'umbraco.resources', 'umbraco.services'])
|
||||
|
||||
// panel main controller
|
||||
.controller("Umbraco.tuningController", function ($scope, $modal, $http, $window, $timeout, $location) {
|
||||
|
||||
$scope.isOpen = false;
|
||||
$scope.frameLoaded = false;
|
||||
$scope.enableTuning = 0;
|
||||
$scope.tuningParameterUrl = "";
|
||||
$scope.tuningGridList = "";
|
||||
$scope.schemaFocus = "body";
|
||||
$scope.settingIsOpen = 'previewDevice';
|
||||
$scope.BackgroundPositions = ['center', 'left', 'right', 'bottom center', 'bottom left', 'bottom right', 'top center', 'top left', 'top right'];
|
||||
$scope.BackgroundRepeats = ['no-repeat', 'repeat', 'repeat-x', 'repeat-y'];
|
||||
$scope.BackgroundAttachments = ['scroll', 'fixed'];
|
||||
$scope.Layouts = ['boxed', 'wide', 'full'];
|
||||
$scope.displays = ['float-left', 'float-right', 'block-left', 'block-right', 'none'];
|
||||
$scope.optionHomes = ['icon', 'text', 'none'];
|
||||
$scope.googleFontFamilies = {};
|
||||
$scope.pageId = "../dialogs/Preview.aspx?id=" + $location.search().id;
|
||||
$scope.devices = [
|
||||
{ name: "desktop", css: "desktop", icon: "icon-display" },
|
||||
{ name: "laptop - 1366px", css: "laptop border", icon: "icon-laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait border", icon: "icon-ipad" },
|
||||
{ name: "iPad landscape - 1024px", css: "iPad-landscape border", icon: "icon-ipad flip" },
|
||||
{ name: "smartphone portrait - 480px", css: "smartphone-portrait border", icon: "icon-iphone" },
|
||||
{ name: "smartphone landscape - 320px", css: "smartphone-landscape border", icon: "icon-iphone flip" }
|
||||
];
|
||||
$scope.previewDevice = $scope.devices[0];
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preview devices */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Set preview device
|
||||
$scope.updatePreviewDevice = function (device) {
|
||||
$scope.previewDevice = device;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* UI designer managment */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Update all tuningConfig's values from data
|
||||
var updateConfigValue = function (data) {
|
||||
|
||||
var fonts = [];
|
||||
$.each(tuningConfig.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
try {
|
||||
|
||||
// value
|
||||
var newValue = eval("data." + field.alias.replace("@", ""));
|
||||
if (newValue != undefined) {
|
||||
field.value = newValue;
|
||||
if (field.value == "''") { field.value = ""; }
|
||||
}
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
|
||||
var fontWeight = eval("data." + field.alias.replace("@", "") + "_weight");
|
||||
var fontStyle = eval("data." + field.alias.replace("@", "") + "_style");
|
||||
var fontType = eval("data." + field.alias.replace("@", "") + "_type");
|
||||
|
||||
if (fontWeight != undefined) {
|
||||
field.fontWeight = fontWeight;
|
||||
if (field.fontWeight == "''") { field.fontWeight = ""; }
|
||||
}
|
||||
|
||||
if (fontStyle != undefined) {
|
||||
field.fontStyle = fontStyle;
|
||||
if (field.fontStyle == "''") { field.fontStyle = ""; }
|
||||
}
|
||||
|
||||
if (fontType != undefined) {
|
||||
field.fontType = fontType;
|
||||
if (field.fontType == "''") { field.fontType = ""; }
|
||||
}
|
||||
|
||||
if (fontType == 'google' && field.value + field.fontWeight && $.inArray(field.value + ":" + field.fontWeight, fonts) < 0) {
|
||||
fonts.splice(0, 0, field.value + ":" + field.fontWeight);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.info("Style parameter not found " + field.alias);
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// Load google font
|
||||
$.each(fonts, function (indexFont, font) {
|
||||
loadGoogleFont(font);
|
||||
loadGoogleFontInFront(font);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Load parameters from GetLessParameters and init data of the tuning config
|
||||
var initTuning = function () {
|
||||
|
||||
$http.get('/Umbraco/Api/tuning/Load', { params: { tuningStyleUrl: $scope.tuningParameterUrl, pageId: $location.search().id } })
|
||||
.success(function (data) {
|
||||
|
||||
updateConfigValue(data);
|
||||
|
||||
$scope.tuningModel = tuningConfig;
|
||||
$scope.tuningPalette = tuningPalette;
|
||||
|
||||
if ($scope.settingIsOpen == "setting") {
|
||||
openIntelTuning();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Add Less parameters for each grid row
|
||||
var initGridConfig = function () {
|
||||
|
||||
if ($scope.tuningGridList) {
|
||||
|
||||
$.each($scope.tuningGridList, function (index, row) {
|
||||
|
||||
var stylingSubSection = tuningConfig.categories[1].sections[0].subSections
|
||||
var newIndex = stylingSubSection.length + 1;
|
||||
var rowFieldModel = angular.copy(rowModel);
|
||||
|
||||
var rowNumber = index + 1;
|
||||
rowFieldModel.name = "Grid Row " + rowNumber;
|
||||
stylingSubSection.splice(newIndex + 1, 0, rowFieldModel);
|
||||
stylingSubSection[newIndex - 1].schema = "." + row;
|
||||
|
||||
$.each(stylingSubSection[newIndex - 1].fields, function (indexField, field) {
|
||||
field.alias = field.alias + "__" + row;
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Refresh all less parameters for every changes watching tuningModel
|
||||
var refreshtuning = function () {
|
||||
var parameters = [];
|
||||
|
||||
if ($scope.tuningModel) {
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
// value
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "':'" + field.value + "'");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "_weight':'" + field.fontWeight + "'");
|
||||
parameters.splice(parameters.length + 1, 0, "'@" + field.alias + "_Style':'" + field.fontStyle + "'");
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// Refrech page style
|
||||
refreshFrontStyles(parameters);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Save all parameter in tuningParameters.less file
|
||||
$scope.saveLessParameters = function () {
|
||||
|
||||
var parameters = [];
|
||||
var parametersGrid = [];
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
if (subSection.schema && subSection.schema.indexOf("gridrow_") >= 0) {
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parametersGrid.splice(parametersGrid.length + 1, 0, "@" + field.alias + ":" + value + ";");
|
||||
}
|
||||
else {
|
||||
// value
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + ":" + value + ";");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
if (field.fontType == "google" && value != "''") {
|
||||
var variant = field.fontWeight != "" || field.fontStyle != "" ? ":" + field.fontWeight + field.fontStyle : "";
|
||||
var gimport = "@import url('http://fonts.googleapis.com/css?family=" + value + variant + "');";
|
||||
if ($.inArray(gimport, parameters) < 0) {
|
||||
parameters.splice(0, 0, gimport);
|
||||
}
|
||||
}
|
||||
var fontWeight = (field.fontWeight != 0 && (field.fontWeight == undefined || field.fontWeight == "")) ? "''" : field.fontWeight;
|
||||
var fontStyle = (field.fontStyle != 0 && (field.fontStyle == undefined || field.fontStyle == "")) ? "''" : field.fontStyle;
|
||||
var fontType = (field.fontType != 0 && (field.fontType == undefined || field.fontType == "")) ? "''" : field.fontType;
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_weight:" + fontWeight + ";");
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_style:" + fontStyle + ";");
|
||||
parameters.splice(parameters.length + 1, 0, "@" + field.alias + "_type:" + fontType + ";");
|
||||
}
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
var resultParameters = { parameters: parameters.join(""), parametersGrid: parametersGrid.join(""), pageId: $location.search().id };
|
||||
var transform = function (result) {
|
||||
return $.param(result);
|
||||
}
|
||||
|
||||
$('.btn-default-save').attr("disabled", true);
|
||||
$http.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
|
||||
$http.post('/Umbraco/Api/tuning/Save', resultParameters, {
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
|
||||
transformRequest: transform
|
||||
})
|
||||
.success(function (data) {
|
||||
$('.btn-default-save').attr("disabled", false);
|
||||
$('#speechbubble').fadeIn('slow').delay(5000).fadeOut('slow');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Delete current page tuning
|
||||
$scope.deleteTuning = function () {
|
||||
$('.btn-default-delete').attr("disabled", true);
|
||||
$http.get('/Umbraco/Api/tuning/Delete', { params: { pageId: $location.search().id } })
|
||||
.success(function (data) {
|
||||
$scope.enableTuning++;
|
||||
$scope.pageId = $scope.pageId + "&n=123456";
|
||||
$('.btn-default-delete').attr("disabled", false);
|
||||
})
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preset design */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Refresh with selected tuning palette
|
||||
$scope.refreshtuningByPalette = function (palette) {
|
||||
updateConfigValue(palette.colors);
|
||||
refreshtuning();
|
||||
}
|
||||
|
||||
// Hidden botton to make preset from the current settings
|
||||
$scope.makePreset = function () {
|
||||
|
||||
var parameters = [];
|
||||
$.each($scope.tuningModel.categories, function (indexCategory, category) {
|
||||
$.each(category.sections, function (indexSection, section) {
|
||||
$.each(section.subSections, function (indexSubSection, subSection) {
|
||||
$.each(subSection.fields, function (indexField, field) {
|
||||
|
||||
if (!subSection.schema || subSection.schema.indexOf("gridrow_") < 0) {
|
||||
|
||||
// value
|
||||
var value = (field.value != 0 && (field.value == undefined || field.value == "")) ? "''" : field.value;
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "\":" + " \"" + value + "\"");
|
||||
|
||||
// special init for font family picker
|
||||
if (field.type == "fontFamilyPicker") {
|
||||
var fontWeight = (field.fontWeight != 0 && (field.fontWeight == undefined || field.fontWeight == "")) ? "''" : field.fontWeight;
|
||||
var fontStyle = (field.fontStyle != 0 && (field.fontStyle == undefined || field.fontStyle == "")) ? "''" : field.fontStyle;
|
||||
var fontType = (field.fontType != 0 && (field.fontType == undefined || field.fontType == "")) ? "''" : field.fontType;
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_weight" + "\":" + " \"" + fontWeight + "\"");
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_style" + "\":" + " \"" + fontStyle + "\"");
|
||||
parameters.splice(parameters.length + 1, 0, "\"" + field.alias + "_type" + "\":" + " \"" + fontType + "\"");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
$("body").append("<textarea>{name:\"\", mainColor:\"\", colors:{" + parameters.join(",") + "}}</textarea>");
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Panel managment */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Toggle panel
|
||||
$scope.togglePanel = function () {
|
||||
if ($scope.isOpen) {
|
||||
$scope.isOpen = false;
|
||||
closeIntelTuning();
|
||||
}
|
||||
else {
|
||||
$scope.isOpen = true;
|
||||
$scope.settingOpen($scope.settingIsOpen);
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle setting
|
||||
$scope.settingOpen = function (a) {
|
||||
|
||||
if ($scope.settingIsOpen == "setting" && a != "setting") {
|
||||
closeIntelTuning();
|
||||
}
|
||||
|
||||
if (a == "setting") {
|
||||
openIntelTuning();
|
||||
}
|
||||
|
||||
$scope.settingIsOpen = a;
|
||||
}
|
||||
|
||||
// Remove value from field
|
||||
$scope.removeField = function (field) {
|
||||
field.value = "";
|
||||
}
|
||||
|
||||
// Open image picker modal
|
||||
$scope.open = function (field) {
|
||||
$scope.data = {
|
||||
newFolder: "",
|
||||
modalField: field
|
||||
};
|
||||
|
||||
var modalInstance = $modal.open({
|
||||
scope: $scope,
|
||||
templateUrl: 'myModalContent.html',
|
||||
controller: 'tuning.mediapickercontroller',
|
||||
resolve: {
|
||||
items: function () {
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function (selectedItem) {
|
||||
field.value = selectedItem;
|
||||
});
|
||||
};
|
||||
|
||||
// Open font family picker modal
|
||||
$scope.openFontFamilyPickerModal = function (field) {
|
||||
$scope.data = {
|
||||
modalField: field
|
||||
};
|
||||
var modalInstance = $modal.open({
|
||||
scope: $scope,
|
||||
templateUrl: 'fontFamilyPickerModel.html',
|
||||
controller: 'tuning.fontfamilypickercontroller',
|
||||
resolve: {
|
||||
googleFontFamilies: function () {
|
||||
return $scope.googleFontFamilies;
|
||||
},
|
||||
item: function () {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
});
|
||||
modalInstance.result.then(function (selectedItem) {
|
||||
field.value = selectedItem.fontFamily;
|
||||
field.fontType = selectedItem.fontType;
|
||||
field.fontWeight = selectedItem.fontWeight;
|
||||
field.fontStyle = selectedItem.fontStyle;
|
||||
});
|
||||
};
|
||||
|
||||
// Accordion open event
|
||||
$scope.accordionOpened = function (schema) {
|
||||
$scope.schemaFocus = schema;
|
||||
}
|
||||
|
||||
// Focus schema in front
|
||||
$scope.accordionWillBeOpened = function (schema) {
|
||||
if (schema) {
|
||||
setSelectedSchema(schema);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Call function into the front-end */
|
||||
/*****************************************************************************/
|
||||
|
||||
var openIntelTuning = function () {
|
||||
if (document.getElementById("resultFrame").contentWindow.initIntelTuning)
|
||||
document.getElementById("resultFrame").contentWindow.initIntelTuning($scope.tuningModel);
|
||||
}
|
||||
|
||||
var closeIntelTuning = function () {
|
||||
if (document.getElementById("resultFrame").contentWindow.closeIntelTuning)
|
||||
document.getElementById("resultFrame").contentWindow.closeIntelTuning($scope.tuningModel);
|
||||
}
|
||||
|
||||
var loadGoogleFontInFront = function (font) {
|
||||
if (document.getElementById("resultFrame").contentWindow.getFont)
|
||||
document.getElementById("resultFrame").contentWindow.getFont(font);
|
||||
}
|
||||
|
||||
var setSelectedSchema = function (schema) {
|
||||
if (document.getElementById("resultFrame").contentWindow.setSelectedSchema)
|
||||
document.getElementById("resultFrame").contentWindow.setSelectedSchema(schema);
|
||||
}
|
||||
|
||||
var refreshFrontStyles = function (parameters) {
|
||||
if (document.getElementById("resultFrame").contentWindow.refrechLayout)
|
||||
document.getElementById("resultFrame").contentWindow.refrechLayout(parameters);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Google font loader, TODO: put together from directive, front and back */
|
||||
/*****************************************************************************/
|
||||
|
||||
var webFontScriptLoaded = false;
|
||||
var loadGoogleFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
loadGoogleFont(font);
|
||||
})
|
||||
.fail(function () {
|
||||
console.log('error loading webfont');
|
||||
});
|
||||
}
|
||||
else {
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading font' + font + ' in UI designer');
|
||||
},
|
||||
active: function () {
|
||||
console.log('loaded font ' + font + ' in UI designer');
|
||||
},
|
||||
inactive: function () {
|
||||
console.log('error loading font ' + font + ' in UI designer');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Init */
|
||||
/*****************************************************************************/
|
||||
|
||||
// Preload of the google font
|
||||
$http.get('/Umbraco/Api/tuning/GetGoogleFont').success(function (data) {
|
||||
$scope.googleFontFamilies = data;
|
||||
})
|
||||
|
||||
// watch framLoaded, only if iframe page have EnableTuning()
|
||||
$scope.$watch("enableTuning", function () {
|
||||
if ($scope.enableTuning > 0) {
|
||||
if ($scope.enableTuning == 1) {
|
||||
initGridConfig();
|
||||
}
|
||||
initTuning();
|
||||
$scope.$watch('tuningModel', function () {
|
||||
refreshtuning();
|
||||
}, true);
|
||||
}
|
||||
}, true)
|
||||
|
||||
// First default load
|
||||
$timeout(function () {
|
||||
// toggle panel
|
||||
$scope.frameLoaded = true;
|
||||
//$timeout(function () { 1000, $scope.togglePanel(); });
|
||||
}, 1000);
|
||||
|
||||
})
|
||||
|
||||
// Image picker controller
|
||||
.controller('tuning.mediapickercontroller', function ($scope, $modalInstance, items, $http, mediaResource, umbRequestHelper, entityResource, mediaHelper) {
|
||||
|
||||
if (mediaHelper && mediaHelper.registerFileResolver) {
|
||||
mediaHelper.registerFileResolver("Umbraco.UploadField", function (property, entity, thumbnail) {
|
||||
if (thumbnail) {
|
||||
|
||||
if (mediaHelper.detectIfImageByExtension(property.value)) {
|
||||
var thumbnailUrl = umbRequestHelper.getApiUrl(
|
||||
"imagesApiBaseUrl",
|
||||
"GetBigThumbnail",
|
||||
[{ originalImagePath: property.value }]);
|
||||
|
||||
return thumbnailUrl;
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
return property.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
var modalFieldvalue = $scope.data.modalField.value;
|
||||
|
||||
$scope.currentFolder = {};
|
||||
$scope.currentFolder.children = [];
|
||||
$scope.currentPath = [];
|
||||
$scope.startNodeId = -1;
|
||||
|
||||
$scope.options = {
|
||||
url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile"),
|
||||
formData: {
|
||||
currentFolder: $scope.startNodeId
|
||||
}
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
$scope.selectedMedia = undefined;
|
||||
|
||||
$scope.submitFolder = function (e) {
|
||||
if (e.keyCode === 13) {
|
||||
e.preventDefault();
|
||||
$scope.$parent.data.showFolderInput = false;
|
||||
|
||||
if ($scope.$parent.data.newFolder && $scope.$parent.data.newFolder != "") {
|
||||
mediaResource
|
||||
.addFolder($scope.$parent.data.newFolder, $scope.currentFolder.id)
|
||||
.then(function (data) {
|
||||
$scope.$parent.data.newFolder = undefined;
|
||||
$scope.gotoFolder(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.gotoFolder = function (folder) {
|
||||
|
||||
if (!folder) {
|
||||
folder = { id: $scope.startNodeId, name: "Media", icon: "icon-folder" };
|
||||
}
|
||||
|
||||
if (folder.id > 0) {
|
||||
var matches = _.filter($scope.currentPath, function (value, index) {
|
||||
if (value.id == folder.id) {
|
||||
value.indexInPath = index;
|
||||
return value;
|
||||
}
|
||||
});
|
||||
|
||||
if (matches && matches.length > 0) {
|
||||
$scope.currentPath = $scope.currentPath.slice(0, matches[0].indexInPath + 1);
|
||||
}
|
||||
else {
|
||||
$scope.currentPath.push(folder);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$scope.currentPath = [];
|
||||
}
|
||||
|
||||
//mediaResource.rootMedia()
|
||||
mediaResource.getChildren(folder.id)
|
||||
.then(function (data) {
|
||||
folder.children = data.items ? data.items : [];
|
||||
|
||||
angular.forEach(folder.children, function (child) {
|
||||
child.isFolder = child.contentTypeAlias == "Folder" ? true : false;
|
||||
|
||||
if (!child.isFolder) {
|
||||
child.thumbnail = mediaHelper.resolveFile(child, true);
|
||||
child.image = mediaHelper.resolveFile(child, false);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.options.formData.currentFolder = folder.id;
|
||||
$scope.currentFolder = folder;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.iconFolder = "glyphicons-icon folder-open"
|
||||
|
||||
$scope.selectMedia = function (media) {
|
||||
|
||||
if (!media.isFolder) {
|
||||
//we have 3 options add to collection (if multi) show details, or submit it right back to the callback
|
||||
$scope.selectedMedia = media;
|
||||
$scope.data.modalField.value = "url(" + $scope.selectedMedia.image + ")";
|
||||
}
|
||||
else {
|
||||
$scope.gotoFolder(media);
|
||||
}
|
||||
};
|
||||
|
||||
//default root item
|
||||
if (!$scope.selectedMedia) {
|
||||
$scope.gotoFolder();
|
||||
}
|
||||
|
||||
$scope.ok = function () {
|
||||
$modalInstance.close($scope.data.modalField.value);
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
$scope.data.modalField.value = modalFieldvalue;
|
||||
$modalInstance.dismiss('cancel');
|
||||
};
|
||||
|
||||
})
|
||||
|
||||
// Font picker controller
|
||||
.controller('tuning.fontfamilypickercontroller', function ($scope, $modalInstance, item, googleFontFamilies, $http) {
|
||||
|
||||
$scope.safeFonts = ["Arial, Helvetica", "Impact", "Lucida Sans Unicode", "Tahoma", "Trebuchet MS", "Verdana", "Georgia", "Times New Roman", "Courier New, Courier"];
|
||||
$scope.fonts = [];
|
||||
$scope.selectedFont = {};
|
||||
|
||||
var originalFont = {};
|
||||
originalFont.fontFamily = $scope.data.modalField.value;
|
||||
originalFont.fontType = $scope.data.modalField.fontType;
|
||||
originalFont.fontWeight = $scope.data.modalField.fontWeight;
|
||||
originalFont.fontStyle = $scope.data.modalField.fontStyle;
|
||||
|
||||
var googleGetWeight = function (googleVariant) {
|
||||
return (googleVariant != undefined && googleVariant != "") ? googleVariant.replace("italic", "") : "";
|
||||
};
|
||||
|
||||
var googleGetStyle = function (googleVariant) {
|
||||
var variantStyle = "";
|
||||
if (googleVariant != undefined && googleVariant != "" && googleVariant.indexOf("italic") >= 0) {
|
||||
variantWeight = googleVariant.replace("italic", "");
|
||||
variantStyle = "italic";
|
||||
}
|
||||
return variantStyle;
|
||||
};
|
||||
|
||||
angular.forEach($scope.safeFonts, function (value, key) {
|
||||
$scope.fonts.push({
|
||||
groupName: "Safe fonts",
|
||||
fontType: "safe",
|
||||
fontFamily: value,
|
||||
fontWeight: "normal",
|
||||
fontStyle: "normal",
|
||||
});
|
||||
});
|
||||
|
||||
angular.forEach(googleFontFamilies.items, function (value, key) {
|
||||
var variants = value.variants;
|
||||
var variant = value.variants.length > 0 ? value.variants[0] : "";
|
||||
var fontWeight = googleGetWeight(variant);
|
||||
var fontStyle = googleGetStyle(variant);
|
||||
$scope.fonts.push({
|
||||
groupName: "Google fonts",
|
||||
fontType: "google",
|
||||
fontFamily: value.family,
|
||||
variants: value.variants,
|
||||
variant: variant,
|
||||
fontWeight: fontWeight,
|
||||
fontStyle: fontStyle
|
||||
});
|
||||
});
|
||||
|
||||
$scope.setStyleVariant = function () {
|
||||
if ($scope.selectedFont != undefined) {
|
||||
return {
|
||||
'font-family': $scope.selectedFont.fontFamily,
|
||||
'font-weight': $scope.selectedFont.fontWeight,
|
||||
'font-style': $scope.selectedFont.fontStyle
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$scope.showFontPreview = function (font) {
|
||||
if (font != undefined && font.fontFamily != "" && font.fontType == "google") {
|
||||
|
||||
// Font needs to be independently loaded in the iframe for live preview to work.
|
||||
document.getElementById("resultFrame").contentWindow.getFont(font.fontFamily + ":" + font.variant);
|
||||
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font.fontFamily + ":" + font.variant]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading');
|
||||
},
|
||||
active: function () {
|
||||
// If $apply isn't called, the new font family isn't applied until the next user click.
|
||||
$scope.$apply(function () {
|
||||
$scope.selectedFont = font;
|
||||
$scope.selectedFont.fontWeight = googleGetWeight($scope.selectedFont.variant);
|
||||
$scope.selectedFont.fontStyle = googleGetStyle($scope.selectedFont.variant);
|
||||
// Apply to the page content as a preview.
|
||||
$scope.data.modalField.value = $scope.selectedFont.fontFamily;
|
||||
$scope.data.modalField.fontType = $scope.selectedFont.fontType;
|
||||
$scope.data.modalField.fontWeight = $scope.selectedFont.fontWeight;
|
||||
$scope.data.modalField.fontStyle = $scope.selectedFont.fontStyle;
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Font is available, apply it immediately in modal preview.
|
||||
$scope.selectedFont = font;
|
||||
// And to page content.
|
||||
$scope.data.modalField.value = $scope.selectedFont.fontFamily;
|
||||
$scope.data.modalField.fontType = $scope.selectedFont.fontType;
|
||||
$scope.data.modalField.fontWeight = $scope.selectedFont.fontWeight;
|
||||
$scope.data.modalField.fontStyle = $scope.selectedFont.fontStyle;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.ok = function () {
|
||||
$modalInstance.close({
|
||||
fontFamily: $scope.selectedFont.fontFamily,
|
||||
fontType: $scope.selectedFont.fontType,
|
||||
fontWeight: $scope.selectedFont.fontWeight,
|
||||
fontStyle: $scope.selectedFont.fontStyle,
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function () {
|
||||
// Discard font change.
|
||||
$modalInstance.close({
|
||||
fontFamily: originalFont.fontFamily,
|
||||
fontType: originalFont.fontType,
|
||||
fontWeight: originalFont.fontWeight,
|
||||
fontStyle: originalFont.fontStyle,
|
||||
});
|
||||
};
|
||||
|
||||
if (item != undefined) {
|
||||
angular.forEach($scope.fonts, function (value, key) {
|
||||
if (value.fontFamily == item.value) {
|
||||
$scope.selectedFont = value;
|
||||
$scope.selectedFont.variant = item.fontWeight + item.fontStyle;
|
||||
$scope.selectedFont.fontWeight = item.fontWeight;
|
||||
$scope.selectedFont.fontStyle = item.fontStyle;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
/*********************************************************************************************************/
|
||||
/* Global function and variable for panel/page com */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
var refrechLayout = function (parameters) {
|
||||
|
||||
// hide preview badget
|
||||
$("#umbracoPreviewBadge").hide();
|
||||
|
||||
var string = "less.modifyVars({" + parameters.join(",") + "})";
|
||||
eval(string);
|
||||
}
|
||||
|
||||
|
||||
/* Fonts loaded in the tuning panel need to be loaded independently in
|
||||
* the content iframe to allow live previewing.
|
||||
*/
|
||||
var webFontScriptLoaded = false;
|
||||
var getFont = function (font) {
|
||||
if (!webFontScriptLoaded) {
|
||||
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
|
||||
.done(function () {
|
||||
webFontScriptLoaded = true;
|
||||
// Recursively call once webfont script is available.
|
||||
getFont(font);
|
||||
})
|
||||
.fail(function () {
|
||||
console.log('error loading webfont');
|
||||
});
|
||||
}
|
||||
else {
|
||||
WebFont.load({
|
||||
google: {
|
||||
families: [font]
|
||||
},
|
||||
loading: function () {
|
||||
console.log('loading font' + font + ' in iframe');
|
||||
},
|
||||
active: function () {
|
||||
console.log('loaded font ' + font + ' in iframe');
|
||||
},
|
||||
inactive: function () {
|
||||
console.log('error loading font ' + font + ' in iframe');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var setSelectedSchema = function (schema) {
|
||||
outlinePosition($(schema));
|
||||
}
|
||||
|
||||
var closeIntelTuning = function (tuningModel) {
|
||||
|
||||
if (tuningModel) {
|
||||
|
||||
$("[tuning-over]").css('outline', 'none');
|
||||
$.each(tuningModel.categories, function (key, category) {
|
||||
$.each(category.sections, function (key, section) {
|
||||
$.each(section.subSections, function (key, subSection) {
|
||||
if (subSection.schema) {
|
||||
$(subSection.schema).unbind();
|
||||
$(subSection.schema).removeAttr("tuning-over");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var initIntelTuning = function (tuningModel) {
|
||||
|
||||
if (tuningModel) {
|
||||
|
||||
// Add tuning-over attr for each schema from config
|
||||
$.each(tuningModel.categories, function (key, category) {
|
||||
$.each(category.sections, function (key, section) {
|
||||
$.each(section.subSections, function (key, subSection) {
|
||||
if (subSection.schema) {
|
||||
$(subSection.schema).attr("tuning-over", subSection.name);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Outline tuning-over
|
||||
$(document).mousemove(function (e) {
|
||||
|
||||
e.stopPropagation();
|
||||
|
||||
var target = $(e.target);
|
||||
while (target.length > 0 && (target.attr('tuning-over') == undefined || target.attr('tuning-over') == '')) {
|
||||
target = target.parent();
|
||||
}
|
||||
|
||||
if (target.attr('tuning-over') != undefined && target.attr('tuning-over') != '') {
|
||||
target.unbind();
|
||||
|
||||
outlinePosition(target);
|
||||
|
||||
target.click(function (e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
console.info(target.attr('tuning-over'));
|
||||
parent.refrechIntelTuning(target.attr('tuning-over'));
|
||||
return false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
outlineHide();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var outlinePosition = function (target) {
|
||||
|
||||
if (target.length > 0 && target.attr('tuning-over') != undefined && target.attr('tuning-over') != '') {
|
||||
|
||||
var localname = target[0].localName;
|
||||
var height = $(target).outerHeight();
|
||||
var width = $(target).outerWidth();
|
||||
var position = $(target).offset();
|
||||
var posY = position.top - $(window).scrollTop();
|
||||
var posX = position.left - $(window).scrollLeft();
|
||||
|
||||
console.info("element select " + localname);
|
||||
|
||||
$("#outline-data").html(target.attr('tuning-over'));
|
||||
$("#outline-data").css('position', 'fixed');
|
||||
$("#outline-data").css('top', posY);
|
||||
$("#outline-data").css('left', posX);
|
||||
$("#outline-data").css('display', 'block');
|
||||
$("#outline-data").css('position', 'fixed');
|
||||
$("#outline-data").css('background-color', 'rgb(164, 198, 253)');
|
||||
$("#outline-data").css('color', '#000000');
|
||||
$("#outline-data").css('padding', '0px 5px 0px 5px');
|
||||
$("#outline-data").css('font-size', '11px');
|
||||
$("#outline-data").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-data").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-data").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-sup").css('display', "block");
|
||||
$("#outline-sup").css('height', "2px");
|
||||
$("#outline-sup").css('width', width + "px");
|
||||
$("#outline-sup").css('position', 'fixed');
|
||||
$("#outline-sup").css('top', posY);
|
||||
$("#outline-sup").css('left', posX);
|
||||
$("#outline-sup").css('background-color', '#a4c6fd');
|
||||
$("#outline-sup").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-sup").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-sup").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-inf").css('display', "block");
|
||||
$("#outline-inf").css('height', "2px");
|
||||
$("#outline-inf").css('width', Number(width + 2) + "px");
|
||||
$("#outline-inf").css('position', 'fixed');
|
||||
$("#outline-inf").css('top', posY + height);
|
||||
$("#outline-inf").css('left', posX);
|
||||
$("#outline-inf").css('background-color', '#a4c6fd');
|
||||
$("#outline-inf").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-inf").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-inf").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-left").css('display', "block");
|
||||
$("#outline-left").css('height', height + "px");
|
||||
$("#outline-left").css('width', "2px");
|
||||
$("#outline-left").css('position', 'fixed');
|
||||
$("#outline-left").css('top', posY);
|
||||
$("#outline-left").css('left', posX);
|
||||
$("#outline-left").css('background-color', '#a4c6fd');
|
||||
$("#outline-left").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-left").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-left").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
$("#outline-right").css('display', "block");
|
||||
$("#outline-right").css('height', height + "px");
|
||||
$("#outline-right").css('width', "2px");
|
||||
$("#outline-right").css('position', 'fixed');
|
||||
$("#outline-right").css('top', posY);
|
||||
$("#outline-right").css('left', posX + width);
|
||||
$("#outline-right").css('background-color', '#a4c6fd');
|
||||
$("#outline-right").css('transition', 'all .05s ease-in-out');
|
||||
$("#outline-right").css('-moz-transition', 'all .05s ease-in-out');
|
||||
$("#outline-right").css('-webkit-transition', 'all .05s ease-in-out');
|
||||
|
||||
}
|
||||
else {
|
||||
outlineHide();
|
||||
console.info("element not found select");
|
||||
}
|
||||
}
|
||||
|
||||
var outlineHide = function () {
|
||||
|
||||
$("#outline-data").css('display', "none");
|
||||
$("#outline-sup").css('display', "none");
|
||||
$("#outline-inf").css('display', "none");
|
||||
$("#outline-right").css('display', "none");
|
||||
$("#outline-left").css('display', "none");
|
||||
|
||||
}
|
||||
|
||||
var initTuningPanel = function () {
|
||||
|
||||
// Looking for grid row
|
||||
var tuningGridList = []
|
||||
$("div[class^='gridrow_']").each(function (index, value) {
|
||||
tuningGridList.splice(tuningGridList.length + 1, 0, $(value).attr("class"))
|
||||
});
|
||||
|
||||
// Init panel
|
||||
if (parent.setFrameIsLoaded) {
|
||||
parent.setFrameIsLoaded(tuningParameterUrl, tuningGridList);
|
||||
}
|
||||
}
|
||||
|
||||
$(function () {
|
||||
|
||||
// Init ouline layer
|
||||
$("body").append("<div id=\"outline-data\"></div><div id=\"outline-sup\"></div><div id=\"outline-inf\"></div><div id=\"outline-left\"></div><div id=\"outline-right\"></div>");
|
||||
|
||||
// Init tuning panel
|
||||
initTuningPanel();
|
||||
|
||||
});
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* Global function and variable for panel/page com */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
/* Called for every tuning-over rollover */
|
||||
var refrechIntelTuning = function (name) {
|
||||
|
||||
var scope = angular.element($("#tuningPanel")).scope();
|
||||
|
||||
if (scope.schemaFocus != name.toLowerCase()) {
|
||||
|
||||
var notFound = true;
|
||||
angular.forEach(scope.tuningModel.categories, function (category, key) {
|
||||
var isContainer = false;
|
||||
angular.forEach(category.sections, function (section, key) {
|
||||
angular.forEach(section.subSections, function (subSection, key) {
|
||||
if (subSection.name && name.toLowerCase() == subSection.name.toLowerCase()) {
|
||||
isContainer = true;
|
||||
notFound = false
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
if (!category.active) {
|
||||
category.active = isContainer;
|
||||
}
|
||||
});
|
||||
if (notFound) {
|
||||
scope.tuningModel.categories[0].active = true;
|
||||
}
|
||||
scope.$apply();
|
||||
|
||||
if (notFound) {
|
||||
scope.schemaFocus = "body";
|
||||
}
|
||||
else {
|
||||
scope.schemaFocus = name.toLowerCase();
|
||||
}
|
||||
|
||||
scope.$apply();
|
||||
}
|
||||
}
|
||||
|
||||
/* Called when the iframe is first loaded */
|
||||
var setFrameIsLoaded = function (tuningParameterUrl, tuningGridList) {
|
||||
var scope = angular.element($("#tuningPanel")).scope();
|
||||
scope.tuningParameterUrl = tuningParameterUrl;
|
||||
scope.tuningGridList = tuningGridList
|
||||
scope.enableTuning++;
|
||||
scope.$apply();
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
/************************************************************************/
|
||||
/* Grid row -ID- */
|
||||
/************************************************************************/
|
||||
|
||||
/***start-lessParam--ID-***/
|
||||
@backgroundRowColor__-ID-:'';
|
||||
@backgroundRowImageOrPattern__-ID-:'';
|
||||
@backgroundRowGradientColor__-ID-:'';
|
||||
@backgroundRowPosition__-ID-:'';
|
||||
@backgroundRowCover__-ID-:'';
|
||||
@backgroundRowRepeat__-ID-:'';
|
||||
@backgroundRowAttachment__-ID-:'';
|
||||
@rowFullSize__-ID-:false;
|
||||
/***end-lessParam--ID-***/
|
||||
|
||||
/***start-gridStyle--ID-***/
|
||||
.Row-cover__-ID- () when (@backgroundRowCover__-ID- = true) {
|
||||
-webkit-background-size: cover;
|
||||
-moz-background-size: cover;
|
||||
-o-background-size: cover;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
.Row-full-size__-ID- () when (@rowFullSize__-ID- = true) {
|
||||
width:100%;
|
||||
padding-right: 0px;
|
||||
padding-left: 0px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px
|
||||
}
|
||||
|
||||
.-ID- {
|
||||
background-color:@backgroundRowColor__-ID-;
|
||||
background: -moz-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -webkit-gradient(linear, left top, left bottom, color-stop(41%,@backgroundRowColor__-ID-), color-stop(100%,@backgroundRowGradientColor__-ID-));
|
||||
background: -webkit-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -o-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: -ms-linear-gradient(top, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background: linear-gradient(to bottom, @backgroundRowColor__-ID- 41%,@backgroundRowGradientColor__-ID- 100%);
|
||||
background-image: @backgroundRowImageOrPattern__-ID-;
|
||||
background-position: @backgroundRowPosition__-ID-;
|
||||
background-repeat: @backgroundRowRepeat__-ID-;
|
||||
background-attachment: @backgroundRowAttachment__-ID-;
|
||||
.Row-cover__-ID-;}
|
||||
|
||||
.-ID- .container {
|
||||
.Row-full-size__-ID-;
|
||||
}
|
||||
|
||||
/***end-gridStyle--ID-***/
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Dialogs.ApprovedColorPickerController", function ($scope, $http, umbPropEditorHelper, assetsService) {
|
||||
assetsService.loadJs("lib/cssparser/cssparser.js")
|
||||
.then(function () {
|
||||
|
||||
var cssPath = $scope.dialogData.cssPath;
|
||||
$scope.cssClass = $scope.dialogData.cssClass;
|
||||
|
||||
$scope.classes = [];
|
||||
|
||||
$scope.change = function (newClass) {
|
||||
$scope.model.value = newClass;
|
||||
}
|
||||
|
||||
$http.get(cssPath)
|
||||
.success(function (data) {
|
||||
var parser = new CSSParser();
|
||||
$scope.classes = parser.parse(data, false, false).cssRules;
|
||||
$scope.classes.splice(0, 0, "noclass");
|
||||
})
|
||||
|
||||
assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/uSky.Grid.ApprovedColorPicker.css");
|
||||
assetsService.loadCss(cssPath);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
<div ng-controller="Umbraco.Dialogs.ApprovedColorController">
|
||||
<div class='CssClassPickerBox {{(class.mSelectorText.substring(1) == cssClass)? "select" : "" }}'
|
||||
ng-click="submit(class.mSelectorText.substring(1))" ng-repeat='class in classes'>
|
||||
<div class='{{class.mSelectorText.substring(1)}}'>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,15 +1,116 @@
|
||||
function ContentEditDialogController($scope) {
|
||||
function ContentEditDialogController($scope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, umbModelMapper, $http) {
|
||||
//setup scope vars
|
||||
$scope.model = {};
|
||||
$scope.model.defaultButton = null;
|
||||
$scope.model.subButtons = [];
|
||||
|
||||
var dialogOptions = $scope.dialogOptions;
|
||||
if(dialogOptions.entity){
|
||||
$scope.model.entity = dialogOptions.entity;
|
||||
$scope.loaded = true;
|
||||
$scope.model.nodeId = 0;
|
||||
|
||||
var dialogOptions = $scope.$parent.dialogOptions;
|
||||
|
||||
if(angular.isObject(dialogOptions.entity)){
|
||||
$scope.model.entity = $scope.filterTabs(dialogOptions.entity, dialogOptions.tabFilter);
|
||||
$scope.loaded = true;
|
||||
}else{
|
||||
|
||||
if (dialogOptions.create) {
|
||||
//we are creating so get an empty content item
|
||||
contentResource.getScaffold(dialogOptions.id, dialogOptions.contentType)
|
||||
.then(function(data) {
|
||||
$scope.loaded = true;
|
||||
$scope.model.entity = $scope.filterTabs(data, dialogOptions.tabFilter);
|
||||
});
|
||||
}
|
||||
else {
|
||||
//we are editing so get the content item from the server
|
||||
contentResource.getById(dialogOptions.id)
|
||||
.then(function(data) {
|
||||
$scope.loaded = true;
|
||||
$scope.model.entity = $scope.filterTabs(data, dialogOptions.tabFilter);
|
||||
|
||||
|
||||
//in one particular special case, after we've created a new item we redirect back to the edit
|
||||
// route but there might be server validation errors in the collection which we need to display
|
||||
// after the redirect, so we will bind all subscriptions which will show the server validation errors
|
||||
// if there are any and then clear them so the collection no longer persists them.
|
||||
serverValidationManager.executeAndClearAllSubscriptions();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function performSave(args) {
|
||||
var deferred = $q.defer();
|
||||
|
||||
$scope.busy = true;
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: args.statusMessage })) {
|
||||
|
||||
args.saveMethod($scope.model.entity, $routeParams.create, fileManager.getFiles())
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, data)
|
||||
});
|
||||
|
||||
$scope.busy = false;
|
||||
deferred.resolve(data);
|
||||
|
||||
}, function (err) {
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
redirectOnFailure: true,
|
||||
err: err,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.model.entity, err.data)
|
||||
});
|
||||
|
||||
$scope.busy = false;
|
||||
deferred.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
$scope.busy = false;
|
||||
deferred.reject();
|
||||
}
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
$scope.filterTabs = function(entity, blackList){
|
||||
if(blackList){
|
||||
_.each(entity.tabs, function(tab){
|
||||
tab.hide = _.contains(blackList, tab.alias);
|
||||
});
|
||||
}
|
||||
|
||||
return entity;
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function() {
|
||||
$scope.submit($scope.model.entity);
|
||||
};
|
||||
|
||||
$scope.saveAndPublish = function() {
|
||||
performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." })
|
||||
.then(function(content){
|
||||
if(dialogOptions.closeOnSave){
|
||||
$scope.submit(content);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.save = function () {
|
||||
performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." })
|
||||
.then(function(content){
|
||||
if(dialogOptions.closeOnSave){
|
||||
$scope.submit(content);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Dialogs.Content.EditController", ContentEditDialogController);
|
||||
@@ -6,12 +6,15 @@
|
||||
|
||||
<div class="umb-panel">
|
||||
<div class="umb-panel-header">
|
||||
<h1>{{model.entity.name}}</h1>
|
||||
<umb-content-name
|
||||
placeholder="@placeholders_entername"
|
||||
ng-model="model.entity.name"/>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer">
|
||||
<div id="tab{{tab.id}}" ng-repeat="tab in model.entity.tabs">
|
||||
<div class="umb-pane">
|
||||
<div class="umb-pane" ng-if="!tab.hide">
|
||||
<h5>{{tab.label}} - {{tab.alias}}</h5>
|
||||
<umb-property
|
||||
property="property"
|
||||
ng-repeat="property in tab.properties">
|
||||
@@ -26,31 +29,31 @@
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
<localize key="general_close">Close</localize>
|
||||
</a>
|
||||
|
||||
|
||||
<div class="btn-group dropup">
|
||||
<!-- primary button -->
|
||||
<a class="btn btn-success" href="#" ng-click="saveAndPublish()" prevent-default>
|
||||
Publish
|
||||
</a>
|
||||
|
||||
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<!-- sub buttons -->
|
||||
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel">
|
||||
<a href ng-click="save()" prevent-default>
|
||||
Save
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="btn-group dropup" ng-if="defaultButton" >
|
||||
<!-- primary button -->
|
||||
<a class="btn btn-success" href="#" ng-click="performAction(model.defaultButton)" prevent-default>
|
||||
<localize key="{{model.defaultButton.labelKey}}">{{defaultButton.labelKey}}</localize>
|
||||
</a>
|
||||
|
||||
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown" ng-if="subButtons.length > 0">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<!-- sub buttons -->
|
||||
<ul class="dropdown-menu bottom-up" role="menu" aria-labelledby="dLabel"
|
||||
ng-if="model.subButtons.length > 0">
|
||||
<li ng-repeat="btn in model.subButtons">
|
||||
<a href="#" ng-click="performAction(btn)" ng-disabled="true" prevent-default>
|
||||
<localize key="{{btn.labelKey}}">{{btn.labelKey}}</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
angular.module("umbraco").controller('Umbraco.Dialogs.Template.QueryBuilderController',
|
||||
function($scope, $http, dialogService){
|
||||
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetAllowedProperties").then(function(response) {
|
||||
$scope.properties = response.data;
|
||||
});
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetContentTypes").then(function (response) {
|
||||
$scope.contentTypes = response.data;
|
||||
});
|
||||
|
||||
$http.get("backoffice/UmbracoApi/TemplateQuery/GetFilterConditions").then(function (response) {
|
||||
$scope.conditions = response.data;
|
||||
});
|
||||
|
||||
|
||||
$scope.query = {
|
||||
contentType: {
|
||||
name: "Everything"
|
||||
},
|
||||
source:{
|
||||
name: "My website"
|
||||
},
|
||||
filters:[
|
||||
{
|
||||
property:undefined,
|
||||
operator: undefined
|
||||
}
|
||||
],
|
||||
sort:{
|
||||
property:{
|
||||
alias: "",
|
||||
name: "",
|
||||
},
|
||||
direction: "Ascending"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
$scope.chooseSource = function(query){
|
||||
dialogService.contentPicker({
|
||||
callback: function (data) {
|
||||
|
||||
if (data.id > 0) {
|
||||
query.source = { id: data.id, name: data.name };
|
||||
} else {
|
||||
query.source.name = "My website";
|
||||
delete query.source.id;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var throttledFunc = _.throttle(function() {
|
||||
|
||||
$http.post("backoffice/UmbracoApi/TemplateQuery/PostTemplateQuery", $scope.query).then(function (response) {
|
||||
$scope.result = response.data;
|
||||
});
|
||||
|
||||
}, 200);
|
||||
|
||||
$scope.$watch("query", function(value) {
|
||||
throttledFunc();
|
||||
}, true);
|
||||
|
||||
$scope.getPropertyOperators = function (property) {
|
||||
|
||||
var conditions = _.filter($scope.conditions, function(condition) {
|
||||
var index = condition.appliesTo.indexOf(property.type);
|
||||
return index >= 0;
|
||||
});
|
||||
return conditions;
|
||||
};
|
||||
|
||||
|
||||
$scope.addFilter = function(query){
|
||||
query.filters.push({});
|
||||
};
|
||||
|
||||
$scope.trashFilter = function (query) {
|
||||
query.filters.splice(query,1);
|
||||
};
|
||||
|
||||
$scope.changeSortOrder = function(query){
|
||||
if(query.sort.direction === "ascending"){
|
||||
query.sort.direction = "descending";
|
||||
}else{
|
||||
query.sort.direction = "ascending";
|
||||
}
|
||||
};
|
||||
|
||||
$scope.setSortProperty = function(query, property){
|
||||
query.sort.property = property;
|
||||
if(property.type === "datetime"){
|
||||
query.sort.direction = "descending";
|
||||
}else{
|
||||
query.sort.direction = "ascending";
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -0,0 +1,158 @@
|
||||
<form novalidate name="contentForm"
|
||||
ng-controller="Umbraco.Dialogs.Template.QueryBuilderController"
|
||||
ng-submit="close()"
|
||||
val-form-manager>
|
||||
|
||||
<style>
|
||||
.umb-querybuilder .row {font-size: 12px; line-height: 12px}
|
||||
|
||||
.umb-querybuilder .row a.btn{font-size: 12px; background: lightyellow}
|
||||
|
||||
.umb-querybuilder .row > div{
|
||||
padding: 20px;
|
||||
border-bottom: 1px solid #efefef;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="umb-panel">
|
||||
|
||||
<div class="umb-panel-header">
|
||||
<h1 class="headline" style="margin: 10px 0 0 0">Build a query</h1>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer umb-querybuilder">
|
||||
|
||||
<div class="row">
|
||||
<div>
|
||||
I want
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{query.contentType.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="contentType in contentTypes">
|
||||
<a href ng-click="query.contentType = contentType">
|
||||
{{contentType.name}}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<span>from</span>
|
||||
|
||||
<a href class="btn btn-link" ng-click="chooseSource(query)">
|
||||
{{query.source.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="filter in query.filters">
|
||||
|
||||
<span ng-if="$first">Where</span>
|
||||
<span ng-if="!$first">And</span>
|
||||
|
||||
<div class="btn-group">
|
||||
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{filter.property.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="property in properties">
|
||||
<a href ng-click="filter.property = property">
|
||||
{{property.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="btn-group" ng-if="filter.property">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{filter.term.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="term in getPropertyOperators(filter.property)">
|
||||
<a href ng-click="filter.term = term">
|
||||
{{term.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<input type="text" ng-if="filter.term" style="width:90px;" ng-model="filter.constraintValue" />
|
||||
|
||||
<a href ng-click="addFilter(query)">
|
||||
<i class="icon-add"></i>
|
||||
</a>
|
||||
|
||||
<a href ng-if="query.filters.length > 1" ng-click="trashFilter(query)">
|
||||
<i class="icon-trash"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div>
|
||||
|
||||
Order by
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-link dropdown-toggle"
|
||||
data-toggle="dropdown" href="#">
|
||||
{{query.sort.property.name}}
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="property in properties">
|
||||
<a href ng-click="setSortProperty(query, property)">
|
||||
{{property.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<a href class="btn" ng-click="changeSortOrder(query)">
|
||||
{{query.sort.direction}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4>Returns {{result.resultCount}} items in {{result.executionTime}} miliseconds</h4>
|
||||
|
||||
<ul class="nav unstyled">
|
||||
<li ng-repeat="item in result.sampleResults">
|
||||
<i class="icon icon-document blue"></i> {{item.name}}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<pre>{{result.queryExpression}}</pre>
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-footer" >
|
||||
<div class="umb-el-wrap umb-panel-buttons">
|
||||
<div class="btn-toolbar umb-btn-toolbar pull-right">
|
||||
<a href ng-click="close()" class="btn btn-link">
|
||||
<localize key="general_close">Close</localize>
|
||||
</a>
|
||||
|
||||
<a href ng-click="submit(result.queryExpression)" class="btn btn-primary">Insert</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -264,10 +264,11 @@ function ContentEditController($scope, $routeParams, $q, $timeout, $window, appS
|
||||
$scope.preview = function (content) {
|
||||
// Chromes popup blocker will kick in if a window is opened
|
||||
// outwith the initial scoped request. This trick will fix that.
|
||||
var previewWindow = $window.open("/umbraco/views/content/umbpreview.html", "umbpreview");
|
||||
//
|
||||
var previewWindow = $window.open('preview/?id=' + content.id, 'umbpreview');
|
||||
$scope.save().then(function (data) {
|
||||
// Build the correct path so both /#/ and #/ work.
|
||||
var redirect = Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + '/dialogs/preview.aspx?id=' + data.id;
|
||||
var redirect = Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + '/preview/?id=' + data.id;
|
||||
previewWindow.location.href = redirect;
|
||||
});
|
||||
};
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
|
||||
|
||||
<div class="umb-tab-buttons" detect-fold ng-class="{'umb-dimmed': busy}">
|
||||
|
||||
<div class="btn-group" ng-show="content.template">
|
||||
<a class="btn" ng-click="preview(content)">
|
||||
<localize key="buttons_showPage">Preview page</localize>
|
||||
|
||||
+106
-94
@@ -4,35 +4,35 @@ angular.module('umbraco')
|
||||
.controller("Umbraco.PropertyEditors.ContentPickerController",
|
||||
|
||||
function($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams){
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
filterCssClass: "not-allowed not-published",
|
||||
|
||||
startNode: {
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
|
||||
//if we have a query for the startnode, we will use that.
|
||||
if($scope.cfg.startNode.query){
|
||||
@@ -44,90 +44,102 @@ angular.module('umbraco')
|
||||
$scope.cfg.startNodeId = $scope.cfg.startNode.id;
|
||||
}
|
||||
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.section = $scope.cfg.startNode.type;
|
||||
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.edit = function (node) {
|
||||
dialogService.open(
|
||||
{
|
||||
template: "views/common/dialogs/content/edit.html",
|
||||
id: node.id,
|
||||
closeOnSave:true,
|
||||
tabFilter: ["Generic properties"],
|
||||
callback: function(data){
|
||||
node.name = data.name;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
$scope.ids = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
//We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
$scope.ids = _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
});
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
|
||||
//Validate!
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.minCount.$setValidity("minCount", true);
|
||||
}
|
||||
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
|
||||
}
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -15,6 +15,7 @@
|
||||
<i class="{{node.icon}} hover-hide"></i>
|
||||
{{node.name}}
|
||||
</a>
|
||||
<br/><small><a href ng-click="edit(node)">Edit</a></small>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
+324
@@ -0,0 +1,324 @@
|
||||
var uSkyGridConfig = [
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 12,
|
||||
percentage: 100,
|
||||
|
||||
cellModels: [
|
||||
{
|
||||
name: "Single column",
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
name: "Article",
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media","quote"]
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte"]
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: "Article, reverse",
|
||||
models: [
|
||||
{
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte","macro"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media","quote","embed"]
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: "Profile page",
|
||||
models: [
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["media"]
|
||||
},
|
||||
{
|
||||
grid: 8,
|
||||
percentage: 66.6,
|
||||
allowed: ["rte"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Headline",
|
||||
models: [
|
||||
{
|
||||
grid: 12,
|
||||
percentage: 100,
|
||||
max: 1,
|
||||
allowed: ["headline"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Three columns",
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
allowed: ["rte"]
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 9,
|
||||
percentage: 70,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}, {
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, ]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 3,
|
||||
percentage: 30,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 3,
|
||||
percentage: 30,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 9,
|
||||
percentage: 70,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}, {
|
||||
grid: 6,
|
||||
percentage: 50
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 33.3
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, {
|
||||
grid: 3,
|
||||
percentage: 25
|
||||
}, ]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}, {
|
||||
grid: 2,
|
||||
percentage: 16.6
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}, {
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}]
|
||||
}, {
|
||||
models: [{
|
||||
grid: 4,
|
||||
percentage: 40
|
||||
}, {
|
||||
grid: 8,
|
||||
percentage: 60
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
columns: [
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
grid: 4,
|
||||
percentage: 33.3,
|
||||
cellModels: [
|
||||
{
|
||||
models: [{
|
||||
grid: 12,
|
||||
percentage: 100
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
body.mce-content-body {
|
||||
background: transparent !important;
|
||||
overflow-x:hidden !important;
|
||||
padding-bottom: 10px !important;
|
||||
/*margin:0px;*/
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 10px;
|
||||
}
|
||||
|
||||
.button {
|
||||
display: inline-block;
|
||||
border-radius:4px;
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
[
|
||||
{
|
||||
"name": "Headline",
|
||||
"alias": "headline",
|
||||
"view": "textstring",
|
||||
"icon": "icon-coin",
|
||||
"config": {
|
||||
"style": "font-size: 36px; font-weight: bold",
|
||||
"markup" : "<h1>#value#</h1>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Quote",
|
||||
"alias": "quote",
|
||||
"view": "textstring",
|
||||
"icon": "icon-quote",
|
||||
"config": {
|
||||
"style": "border-left: 3px solid #ccc; padding: 10px; color: #ccc; font-family: serif; font-variant: italic; font-size: 18px",
|
||||
"markup": "<blockquote>#value#</blockquote>"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Rich text editor",
|
||||
"alias": "rte",
|
||||
"view": "rte",
|
||||
"icon": "icon-article"
|
||||
},
|
||||
{
|
||||
"name": "Media",
|
||||
"alias": "media",
|
||||
"view": "media",
|
||||
"icon": "icon-picture"
|
||||
},
|
||||
{
|
||||
"name": "Macro",
|
||||
"alias": "macro",
|
||||
"view": "macro",
|
||||
"icon": "icon-settings-alt"
|
||||
},
|
||||
{
|
||||
"name": "Embed",
|
||||
"alias": "embed",
|
||||
"view": "embed",
|
||||
"icon": "icon-movie-alt"
|
||||
}
|
||||
]
|
||||
@@ -1,13 +0,0 @@
|
||||
/*
|
||||
|
||||
body{
|
||||
background: white;
|
||||
}
|
||||
|
||||
.editor{padding: 20px; margin: 20px; border: 3px dashed black; }
|
||||
.editor:hover{border-color: red;}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.EmbedController",
|
||||
function ($scope, $rootScope, $timeout, dialogService) {
|
||||
|
||||
$scope.setEmbed = function(){
|
||||
dialogService.embedDialog({
|
||||
callback: function (data) {
|
||||
$scope.control.value = data;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setEmbed();
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.EmbedController">
|
||||
|
||||
<div class="usky-editor-placeholder" ng-click="setEmbed()" ng-if="control.value === null">
|
||||
<i class="icon icon-movie-alt"></i>
|
||||
<div class="help-text">Click to embed</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="control.value" ng-bind-html-unsafe="control.value"></div>
|
||||
</div>
|
||||
@@ -0,0 +1,42 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.MacroController",
|
||||
function ($scope, $rootScope, $timeout, dialogService, macroResource, macroService, $routeParams) {
|
||||
|
||||
$scope.title = "Click to insert macro";
|
||||
$scope.setMacro = function(){
|
||||
dialogService.macroPicker({
|
||||
callback: function (data) {
|
||||
|
||||
$scope.control.value = {
|
||||
syntax: data.syntax,
|
||||
macroAlias: data.macroAlias,
|
||||
marcoParamsDictionary: data.macroParamsDictionary
|
||||
};
|
||||
|
||||
$scope.setPreview(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setPreview = function(macro){
|
||||
var contentId = $routeParams.id;
|
||||
|
||||
macroResource.getMacroResultAsHtmlForEditor(macro.macroAlias, contentId, macro.macroParamsDictionary)
|
||||
.then(function (htmlResult) {
|
||||
$scope.title = macro.macroAlias;
|
||||
if(htmlResult.trim().length > 0 && htmlResult.indexOf("Macro:") < 0){
|
||||
$scope.preview = htmlResult;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setMacro();
|
||||
}else{
|
||||
var parsed = macroService.parseMacroSyntax($scope.control.value.syntax);
|
||||
$scope.setPreview(parsed);
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.MacroController">
|
||||
|
||||
<div class="usky-editor-placeholder" ng-click="setMacro()">
|
||||
<div ng-if="!preview">
|
||||
<i class="icon icon-settings-alt"></i>
|
||||
<div class="help-text">{{title}}</div>
|
||||
</div>
|
||||
<div ng-if="preview">
|
||||
<div
|
||||
ng-if="preview" style="text-align: left"
|
||||
ng-bind-html-unsafe="preview">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,23 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.MediaController",
|
||||
function ($scope, $rootScope, $timeout, dialogService) {
|
||||
|
||||
$scope.setImage = function(){
|
||||
dialogService.mediaPicker({
|
||||
multiPicker: false,
|
||||
callback: function (data) {
|
||||
$scope.control.value = {
|
||||
id: data.id,
|
||||
image: data.image,
|
||||
thumbnail: data.thumbnail
|
||||
};
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$timeout(function(){
|
||||
if($scope.control.value === null){
|
||||
$scope.setImage();
|
||||
}
|
||||
}, 200);
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.MediaController">
|
||||
|
||||
<div class="usky-editor-placeholder" ng-click="setImage()" ng-if="control.value === null">
|
||||
<i class="icon icon-picture"></i>
|
||||
<div class="help-text">Click to insert image</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="control.value">
|
||||
<img
|
||||
ng-if="control.value"
|
||||
ng-click="setImage()"
|
||||
ng-src="{{control.value.image}}"
|
||||
class="fullSizeImage" />
|
||||
<input type="text" class="caption" ng-model="control.value.caption" placeholder="Image caption..."/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
<div
|
||||
unique-id="control.uniqueId"
|
||||
value="control.value"
|
||||
grid-rte configuration="model.config.rte"></div>
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.Grid.TextStringController",
|
||||
function ($scope, $rootScope, $timeout, dialogService) {
|
||||
|
||||
$scope.adjustSize = function(ev){
|
||||
if(ev.target.scrollHeight > ev.target.clientHeight){
|
||||
$(ev.target).height(ev.target.scrollHeight);
|
||||
}
|
||||
};
|
||||
|
||||
if($scope.control.value === null){
|
||||
$timeout(function(){
|
||||
$("#" + $scope.control.uniqueId +"_text").focus();
|
||||
}, 200);
|
||||
}
|
||||
|
||||
});
|
||||
@@ -0,0 +1,3 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.Grid.TextStringController">
|
||||
<textarea class="textstring" id="{{control.uniqueId}}_text" ng-keyup="adjustSize($event)" ng-model="control.value" style="{{control.editor.config.style}}" placeholder="Write here..."></textarea>
|
||||
</div>
|
||||
@@ -1,52 +1,262 @@
|
||||
'use strict';
|
||||
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridController",
|
||||
function($rootScope, $scope, dialogService, $log){
|
||||
//we most likely will need some iframe-motherpage interop here
|
||||
|
||||
//we most likely will need some iframe-motherpage interop here
|
||||
$scope.openMediaPicker =function(){
|
||||
var d = dialogService.mediaPicker({callback: renderImages});
|
||||
};
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridController",
|
||||
function ($scope, $http, assetsService, $rootScope, dialogService, gridService, mediaResource, imageHelper, $timeout) {
|
||||
|
||||
$scope.openPropertyDialog =function(){
|
||||
var d = dialogService.property({callback: renderProperty});
|
||||
};
|
||||
var gridConfigPath = $scope.model.config.items.gridConfigPath;
|
||||
|
||||
$scope.openMacroDialog =function(){
|
||||
var d = dialogService.macroPicker({callback: renderMacro});
|
||||
};
|
||||
if(!gridConfigPath){
|
||||
gridConfigPath = "views/propertyeditors/grid/grid.default.config.js";
|
||||
}
|
||||
|
||||
function renderProperty(data){
|
||||
$scope.currentElement.html("<h1>boom, property!</h1>");
|
||||
}
|
||||
assetsService.loadJs(gridConfigPath).then(function(){
|
||||
|
||||
function renderMacro(data){
|
||||
// $scope.currentElement.html( macroFactory.renderMacro(data.macro, -1) );
|
||||
}
|
||||
|
||||
function renderImages(data) {
|
||||
var list = $("<ul class='thumbnails'></ul>");
|
||||
$.each(data.selection, function(i, image) {
|
||||
list.append( $("<li class='span2'><img class='thumbnail' src='" + image.src + "'></li>") );
|
||||
});
|
||||
// Grid config
|
||||
$scope.uSkyGridConfig = uSkyGridConfig;
|
||||
|
||||
$scope.currentElement.html( list[0].outerHTML);
|
||||
}
|
||||
// Grid status variables
|
||||
$scope.currentRow = null;
|
||||
$scope.currentCell = null;
|
||||
$scope.currentToolsControl = null;
|
||||
$scope.currentControl = null;
|
||||
$scope.openRTEToolbarId = null;
|
||||
|
||||
$(window).bind("umbraco.grid.click", function(event){
|
||||
gridService.getGridEditors().then(function(response){
|
||||
$scope.availableEditors = response.data;
|
||||
});
|
||||
|
||||
// *********************************************
|
||||
// Sortable options
|
||||
// *********************************************
|
||||
|
||||
$scope.$apply(function () {
|
||||
$scope.currentEditor = event.editor;
|
||||
$scope.currentElement = $(event.element);
|
||||
$scope.sortableOptions = {
|
||||
distance: 10,
|
||||
cursor: "move",
|
||||
placeholder: 'ui-sortable-placeholder',
|
||||
handle: '.cell-tools-move',
|
||||
start: function (e, ui) {
|
||||
ui.item.find('.mceNoEditor').each(function () {
|
||||
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
|
||||
|
||||
if(event.editor == "macro")
|
||||
$scope.openMacroDialog();
|
||||
else if(event.editor == "image")
|
||||
$scope.openMediaPicker();
|
||||
else
|
||||
$scope.propertyDialog();
|
||||
});
|
||||
})
|
||||
});
|
||||
});
|
||||
},
|
||||
stop: function (e, ui) {
|
||||
ui.item.find('.mceNoEditor').each(function () {
|
||||
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// *********************************************
|
||||
// Template management functions
|
||||
// *********************************************
|
||||
|
||||
$scope.checkContent = function() {
|
||||
var isEmpty = true;
|
||||
if ($scope.model.value &&
|
||||
$scope.model.value.columns) {
|
||||
angular.forEach($scope.model.value.columns, function (value, key) {
|
||||
if ( value.rows && value.rows.length > 0) {
|
||||
isEmpty = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isEmpty)
|
||||
{
|
||||
$scope.model.value = undefined;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$scope.addTemplate = function (template) {
|
||||
$scope.model.value = {
|
||||
gridWidth: "",
|
||||
columns: []
|
||||
};
|
||||
|
||||
angular.forEach(template.columns, function (value, key) {
|
||||
var newCol = angular.copy(value);
|
||||
newCol.rows = [];
|
||||
$scope.model.value.columns.splice($scope.model.value.columns.length + 1, 0, newCol);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// *********************************************
|
||||
// Row management function
|
||||
// *********************************************
|
||||
|
||||
$scope.setCurrentRow = function (row) {
|
||||
$scope.currentRow = row;
|
||||
}
|
||||
|
||||
$scope.disableCurrentRow = function () {
|
||||
$scope.currentRow = null;
|
||||
}
|
||||
|
||||
|
||||
$scope.addRow = function (column, cellModel) {
|
||||
|
||||
column.rows.splice(column.rows.length + 1, 0,
|
||||
{
|
||||
uniqueId: $scope.setUniqueId(),
|
||||
cells: [],
|
||||
cssClass: ''
|
||||
});
|
||||
|
||||
for (var i = 0; i < cellModel.models.length; i++) {
|
||||
|
||||
var cells = column.rows[column.rows.length - 1].cells;
|
||||
var model = angular.copy(cellModel.models[i]);
|
||||
|
||||
cells.splice(
|
||||
cells.length + 1, 0,
|
||||
{
|
||||
model: model,
|
||||
controls: []
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeRow = function (column, $index) {
|
||||
if (column.rows.length > 0) {
|
||||
column.rows.splice($index, 1);
|
||||
$scope.openRTEToolbarId = null;
|
||||
$scope.checkContent();
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************
|
||||
// Cell management functions
|
||||
// *********************************************
|
||||
|
||||
$scope.setCurrentCell = function (cell) {
|
||||
$scope.currentCell = cell;
|
||||
}
|
||||
|
||||
$scope.disableCurrentCell = function (cell) {
|
||||
$scope.currentCell = null;
|
||||
}
|
||||
|
||||
$scope.cellPreview = function(cell){
|
||||
if($scope.availableEditors && cell && cell.allowed && angular.isArray(cell.allowed)){
|
||||
var editor = $scope.getEditor(cell.allowed[0]);
|
||||
return editor.icon;
|
||||
}else{
|
||||
return "icon-layout";
|
||||
}
|
||||
}
|
||||
|
||||
// *********************************************
|
||||
// Control management functions
|
||||
// *********************************************
|
||||
$scope.setCurrentControl = function (Control) {
|
||||
$scope.currentControl = Control;
|
||||
};
|
||||
|
||||
$scope.disableCurrentControl = function (Control) {
|
||||
$scope.currentControl = null;
|
||||
};
|
||||
|
||||
$scope.setCurrentToolsControl = function (Control) {
|
||||
$scope.currentToolsControl = Control;
|
||||
};
|
||||
|
||||
$scope.disableCurrentToolsControl = function (Control) {
|
||||
$scope.currentToolsControl = null;
|
||||
};
|
||||
|
||||
$scope.setCurrentRemoveControl = function (Control) {
|
||||
$scope.currentRemoveControl = Control;
|
||||
};
|
||||
|
||||
$scope.disableCurrentRemoveControl = function (Control) {
|
||||
$scope.currentRemoveControl = null;
|
||||
};
|
||||
|
||||
$scope.setCurrentMoveControl = function (Control) {
|
||||
$scope.currentMoveControl = Control;
|
||||
};
|
||||
|
||||
$scope.disableCurrentMoveControl = function (Control) {
|
||||
$scope.currentMoveControl = null;
|
||||
};
|
||||
|
||||
$scope.setUniqueId = function (cell, index) {
|
||||
var date = new Date();
|
||||
var components = [
|
||||
date.getYear(),
|
||||
date.getMonth(),
|
||||
date.getDate(),
|
||||
date.getHours(),
|
||||
date.getMinutes(),
|
||||
date.getSeconds(),
|
||||
date.getMilliseconds()
|
||||
];
|
||||
return components.join("");
|
||||
};
|
||||
|
||||
$scope.setEditorPath = function(control){
|
||||
control.editorPath = "views/propertyeditors/grid/editors/" + control.editor.view + ".html";
|
||||
};
|
||||
|
||||
$scope.addControl = function (editor, cell, index){
|
||||
var newId = $scope.setUniqueId();
|
||||
var newControl = {
|
||||
uniqueId: newId,
|
||||
value: null,
|
||||
editor: editor
|
||||
};
|
||||
|
||||
if (index === undefined) {
|
||||
index = cell.controls.length;
|
||||
}
|
||||
|
||||
cell.controls.splice(index + 1, 0, newControl);
|
||||
};
|
||||
|
||||
$scope.addTinyMce = function(cell){
|
||||
var rte = _.find($scope.availableEditors, function(editor){return editor.alias === "rte";});
|
||||
$scope.addControl(rte, cell);
|
||||
};
|
||||
|
||||
$scope.getEditor = function(alias){
|
||||
return _.find($scope.availableEditors, function(editor){return editor.alias === alias});
|
||||
};
|
||||
|
||||
$scope.removeControl = function (cell, $index) {
|
||||
cell.controls.splice($index, 1);
|
||||
};
|
||||
|
||||
$scope.allowedControl = function (editor, cell){
|
||||
if(cell.model.allowed && angular.isArray(cell.model.allowed)){
|
||||
return _.contains(cell.model.allowed, editor.alias);
|
||||
}else{
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// *********************************************
|
||||
// Init grid
|
||||
// *********************************************
|
||||
|
||||
/* init grid data */
|
||||
if ($scope.model.value && $scope.model.value != "") {
|
||||
if (!$scope.model.config.items.enableGridWidth) {
|
||||
$scope.model.value.gridWidth = $scope.model.config.items.defaultGridWith;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.checkContent();
|
||||
|
||||
});
|
||||
|
||||
// *********************************************
|
||||
// asset styles
|
||||
// *********************************************
|
||||
|
||||
//assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/jquery-ui-1.10.4.custom/css/ui-lightness/jquery-ui-1.10.4.custom.min.css");
|
||||
//assetsService.loadCss($scope.model.config.items.approvedBackgroundCss);
|
||||
|
||||
});
|
||||
@@ -1,3 +1,246 @@
|
||||
<div class="umb-editor umb-grid" ng-controller="Umbraco.PropertyEditors.GridController" auto-scale="10">
|
||||
<iframe style="width: 100%; height: 100%;" src="views/propertyeditors/grid/iframe.html"></iframe>
|
||||
<div ng-controller="Umbraco.PropertyEditors.GridController" class="usky-grid">
|
||||
|
||||
|
||||
<!-- Template picker -->
|
||||
<div class="uSky-templates tb" ng-show="!model.value || model.value == ''">
|
||||
<div class="tr">
|
||||
<div class="td middle">
|
||||
<div class="uSky-templates-template" ng-repeat="template in uSkyGridConfig" style="">
|
||||
<div class="tb" ng-click="addTemplate(template)">
|
||||
<div class="tr">
|
||||
<div class="td uSky-templates-column"
|
||||
ng-class="{last:$last}"
|
||||
ng-repeat="column in template.columns"
|
||||
style="width:{{ column.percentage }}%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br/>
|
||||
<div class="help-text">To start, select a layout for your grid</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- template picker end -->
|
||||
|
||||
<!-- Grids -->
|
||||
<div class="usky-grid-width" style="width:{{ model.value.gridWidth }}px">
|
||||
<div class="tb">
|
||||
|
||||
<!-- for each column in model -->
|
||||
<div
|
||||
class="usky-column td"
|
||||
ng-class="{last:$index==model.value.columns.length-1}"
|
||||
ng-repeat="column in model.value.columns"
|
||||
style="width:{{column .percentage}}%">
|
||||
|
||||
<div ui-sortable="sortableOptions" ng-model="column.rows">
|
||||
|
||||
<!-- for each row in column -->
|
||||
<div
|
||||
ng-repeat="row in column.rows"
|
||||
class="usky-row"
|
||||
ng-mouseover="setCurrentRow(row)"
|
||||
ng-mouseleave="disableCurrentRow()"
|
||||
ng-class="{removingControl:currentRemoveControl == row, movingControl:currentMoveControl == row}">
|
||||
|
||||
<!-- Row tool -->
|
||||
<div class="row-tools" ng-animate="'fade'"
|
||||
ng-if="currentRow == row && currentControl === null">
|
||||
|
||||
<!-- delete row -->
|
||||
<div class="cell-tools-remove">
|
||||
<div class="iconBox"
|
||||
ng-click="deletePrompt = true"
|
||||
ng-mouseover="setCurrentRemoveControl(row)"
|
||||
ng-mouseleave="disableCurrentRemoveControl(row)">
|
||||
|
||||
<span ng-if="deletePrompt">
|
||||
Are you sure?
|
||||
<a href style="text-decoration: underline" ng-click="removeRow(column, $index)">Yes</a>
|
||||
</span>
|
||||
|
||||
<i ng-if="!deletePrompt" class="icon icon-trash"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell-tools-move">
|
||||
<div class="iconBox"
|
||||
ng-mouseover="setCurrentMoveControl(row)"
|
||||
ng-mouseleave="disableCurrentMoveControl(row)">
|
||||
<i class="icon icon-navigation"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- row container -->
|
||||
<div
|
||||
ng-class="{last:$index==model.value.length-1,first:$first}"
|
||||
class="{{row.cssClass}} mainContainer">
|
||||
|
||||
<div class="mainTb">
|
||||
<div class="tb">
|
||||
<div class="tr">
|
||||
|
||||
<!-- cells in row -->
|
||||
<div
|
||||
style="width:{{ cell.model.percentage }}%"
|
||||
ng-class="{last:$index==row.cells.length-1,first:$first}"
|
||||
class="td mainTd usky-cell"
|
||||
ng-repeat="cell in row.cells">
|
||||
|
||||
<!-- if cell is empty tools -->
|
||||
<div
|
||||
class="usky-control usky-control-placeholder"
|
||||
ng-if="cell.controls.length == 0">
|
||||
|
||||
<div
|
||||
ng-if="cell.model.allowed && cell.model.allowed.length === 1"
|
||||
ng-init="singleEditor = getEditor(cell.model.allowed[0])"
|
||||
class="cell-tools-add-single single-editor-{{singleEditor.alias}}">
|
||||
|
||||
<a href ng-click="addControl(singleEditor, cell)">
|
||||
<i class="icon {{singleEditor.icon}}"></i>
|
||||
<div class="help-text">{{singleEditor.name}}</div>
|
||||
</a>
|
||||
|
||||
<p class="placeholder" ng-click="addControl(singleEditor, cell)">
|
||||
Start writing here...
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-if="!cell.model.allowed || cell.model.allowed.length > 1">
|
||||
|
||||
<p class="placeholder" ng-click="addTinyMce(cell)">
|
||||
Start writing here...
|
||||
</p>
|
||||
|
||||
<div class="cell-tools-add">
|
||||
<div
|
||||
class="iconBox"
|
||||
ng-repeat="editor in availableEditors track by editor.alias"
|
||||
ng-click="addControl(editor,cell)"
|
||||
ng-show="allowedControl(editor, cell)">
|
||||
<i class="icon {{editor.icon}}"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Controls in cell -->
|
||||
<div
|
||||
ng-repeat="control in cell.controls"
|
||||
ng-class="{last:$index==cell.controls.length-1,
|
||||
removingControl:currentRemoveControl == control,
|
||||
toolsControl:currentToolsControl == control,
|
||||
selectedControl:currentControl == control}"
|
||||
ng-mouseover="setCurrentControl(control)"
|
||||
ng-mouseleave="disableCurrentControl(control)"
|
||||
ng-init="setEditorPath(control); controlIndex = $index;"
|
||||
class="usky-control">
|
||||
|
||||
|
||||
<!-- Filled cell tools -->
|
||||
<div class="cell-tools"
|
||||
ng-animate="'fade'"
|
||||
ng-if="control && ( currentControl == control)">
|
||||
|
||||
|
||||
<div class="cell-tools-add"
|
||||
ng-if="cell.model.max === undefined || cell.model.max < cell.controls.length"
|
||||
ng-mouseover="setCurrentToolsControl(control)"
|
||||
ng-mouseleave="disableCurrentToolsControl(control)">
|
||||
|
||||
<div
|
||||
class="iconBox"
|
||||
ng-repeat="editor in availableEditors"
|
||||
ng-click="addControl(editor,cell, controlIndex)"
|
||||
ng-show="(currentToolsControl == control) && allowedControl(editor, cell)">
|
||||
<i class="icon {{editor.icon}}"></i>
|
||||
</div>
|
||||
|
||||
<div class="iconBox"
|
||||
ng-if="currentToolsControl != control">
|
||||
<i class=" icon icon-add"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- delete cell -->
|
||||
<div class="cell-tools-remove">
|
||||
<div class="iconBox"
|
||||
ng-click="deletePrompt = true"
|
||||
ng-mouseover="setCurrentRemoveControl(control)"
|
||||
ng-mouseleave="disableCurrentRemoveControl(control)">
|
||||
|
||||
<span ng-if="deletePrompt">
|
||||
Are you sure?
|
||||
<a href style="text-decoration: underline" ng-click="removeControl(cell, controlIndex)">Yes</a>
|
||||
</span>
|
||||
|
||||
<i ng-if="!deletePrompt" class="icon icon-trash"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Redering the editor for specific control -->
|
||||
<div
|
||||
ng-if="control && control.editorPath"
|
||||
ng-include="control.editorPath"
|
||||
class="usky-cell usky-cell-{{control.editor.view}}">
|
||||
</div>
|
||||
</div>
|
||||
<!-- Controls repeat end -->
|
||||
|
||||
</div>
|
||||
<!-- cells repeat end -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- row container end -->
|
||||
|
||||
</div>
|
||||
<!-- row repeat -->
|
||||
|
||||
</div>
|
||||
<!-- row sortable end -->
|
||||
|
||||
<!-- column tools -->
|
||||
<div class="usky-templates-columns tb">
|
||||
|
||||
<div class="tr">
|
||||
<div class="td middle">
|
||||
<ul>
|
||||
<li ng-repeat="cellModel in column.cellModels">
|
||||
<div class="tb mainTbpt" ng-click="addRow(column, cellModel)">
|
||||
<div class="tr">
|
||||
<div style="width:{{ cell.percentage; }}%" class="middle mainTdpt td" ng-repeat="cell in cellModel.models">
|
||||
<i class="icon {{cellPreview(cell)}}"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<small>{{cellModel.name}}</small>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="tr">
|
||||
<div class="td middle">
|
||||
<br/>
|
||||
<span class="help-text">Add rows to your layout</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- column tools end -->
|
||||
|
||||
</div>
|
||||
<!-- column repeat end -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<!-- grid wrapper end -->
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridPrevalueEditorController",
|
||||
function ($scope, $http, assetsService, $rootScope, dialogService, mediaResource, gridService, imageHelper, $timeout) {
|
||||
|
||||
var emptyModel = {
|
||||
enableGridWidth: true,
|
||||
defaultGridWith: "",
|
||||
enableBackground: true,
|
||||
enableSkipTopMargin: true,
|
||||
defaultSkipTopMargin: false,
|
||||
enableSkipBottomMargin: true,
|
||||
defaultSkipBottomMargin: false,
|
||||
enableSkipLeftMargin: true,
|
||||
defaultSkipLeftMargin: false,
|
||||
enableSkipRightMargin: true,
|
||||
defaultSkipRightMargin: false,
|
||||
enableSkipControlMargin: true,
|
||||
defaultSkipControlMargin: false,
|
||||
enableFullScreen: true,
|
||||
defaultFullScreen: false,
|
||||
enableBoxed: true,
|
||||
defaultBoxed: false,
|
||||
enableRte: true,
|
||||
enableMedia: true,
|
||||
enableMacro: true,
|
||||
enabledEditors: [ "rte", "media", "macro" ],
|
||||
enableMultiCells: true,
|
||||
approvedBackgroundCss: "",
|
||||
gridConfigPath: "views/propertyeditors/grid/config/grid.default.config.js"
|
||||
}
|
||||
|
||||
gridService.getGridEditors().then(function(response){
|
||||
$scope.editors = response.data;
|
||||
});
|
||||
|
||||
/* init grid data */
|
||||
if (!$scope.model.value || $scope.model.value == "") {
|
||||
$scope.model.value = emptyModel;
|
||||
}
|
||||
|
||||
})
|
||||
@@ -0,0 +1,109 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.GridPrevalueEditorController">
|
||||
|
||||
<p><strong>Config file path:</strong></p>
|
||||
<table cellpadding="20" style="margin-bottom:20px">
|
||||
<tr>
|
||||
<td>
|
||||
<input ng-model="model.value.gridConfigPath" type="text" style="width:500px;">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<!--<p><strong>Allowed row settings:</strong></p>
|
||||
<table cellpadding="20" style="margin-bottom:20px">
|
||||
<tr>
|
||||
<td>
|
||||
<p><i class="icon icon-paint-roller"></i> Enable/Disable row background</p>
|
||||
<input ng-model="model.value.enableBackground" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
</td>
|
||||
<td>
|
||||
<p><i class="icon icon-navigation-top"></i> Enable/Disable top margin</p>
|
||||
<input ng-model="model.value.enableSkipTopMargin" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultSkipTopMargin" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
<td>
|
||||
<p><i class="icon icon-navigation-bottom"></i> Enable/Disable bottom margin</p>
|
||||
<input ng-model="model.value.enableSkipBottomMargin" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultSkipBottomMargin" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><i class="icon icon-navigation-first"></i> Enable/Disable left margin</p>
|
||||
<input ng-model="model.value.enableSkipLeftMargin" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultSkipLeftMargin" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
<td>
|
||||
<p><i class="icon icon-navigation-last"></i> Enable/Disable right margin</p>
|
||||
<input ng-model="model.value.enableSkipRightMargin" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultSkipRightMargin" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
<td>
|
||||
<p><i class="icon icon-fullscreen"></i> Enable/Disable control margin</p>
|
||||
<input ng-model="model.value.enableSkipControlMargin" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultSkipControlMargin" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p><i class="icon icon-width"></i> Enable/Disable full screen</p>
|
||||
<input ng-model="model.value.enableFullScreen" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultFullScreen" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
<td>
|
||||
<p><i class="icon icon-frame"></i> Enable/Disable boxed</p>
|
||||
<input ng-model="model.value.enableBoxed" type="checkbox">
|
||||
<label for="">Enable</label>
|
||||
<br />
|
||||
<input ng-model="model.value.defaultBoxed" type="checkbox">
|
||||
<label for="">Default value</label>
|
||||
</td>
|
||||
</tr>
|
||||
</table>-->
|
||||
|
||||
<!--<p><strong>Allowed editors:</strong></p>
|
||||
<table cellpadding="20" style="margin-bottom:20px">
|
||||
<tr>
|
||||
<td>
|
||||
<p ng-repeat="editor in editors">
|
||||
<input type="checkbox"
|
||||
checklist-model="model.value.enabledEditors"
|
||||
checklist-value="editor.alias">
|
||||
<i class="icon {{editor.icon}}"></i> {{editor.name}}
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>-->
|
||||
|
||||
<p><strong>Others settings:</strong></p>
|
||||
<table cellpadding="20" style="margin-bottom:20px">
|
||||
<tr>
|
||||
<td>
|
||||
<p><input ng-model="model.value.enableMultiCells" type="checkbox"> <i class="icon icon-edit"></i> Multiple controls in cell</p>
|
||||
<!--<p>Approved background stylesheet path: <input ng-model="model.value.approvedBackgroundCss" type="text" style="width:300px;"></p>-->
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
@@ -1,69 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="../../../assets/css/umbraco.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="row-fluid">
|
||||
<div class="span12" data-editor="rte">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Headline
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span6" data-editor="rte">
|
||||
Rich Text editor
|
||||
</div>
|
||||
<div class="span6" data-editor="macro">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Insert macro
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span4" data-editor="macro">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Insert Macro
|
||||
</div>
|
||||
<div class="span4" data-editor="image">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Insert image
|
||||
</div>
|
||||
<div class="span4" data-editor="image">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Insert image
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12" data-editor="rte">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Rich Text editor
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-fluid">
|
||||
<div class="span12" data-editor="rte">
|
||||
<i class="icon-move"></i>
|
||||
<i class="icon-edit"></i>
|
||||
<i class="icon-trash"></i>
|
||||
Footer
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="../../../lib/jquery/jquery-2.0.3.min.js"></script>
|
||||
<script src="js/iframe.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,19 +0,0 @@
|
||||
$(function(){
|
||||
var editors = $('[data-editor]');
|
||||
var p = parent.$(parent.document);
|
||||
|
||||
|
||||
editors.addClass("editor");
|
||||
|
||||
editors.on("click", function (event) {
|
||||
event.preventDefault();
|
||||
|
||||
// parent.document.fire("umbraco.grid.click");
|
||||
var el = this;
|
||||
var e = jQuery.Event("umbraco.grid.click", {editor: $(el).data("editor"), element: el});
|
||||
p.trigger( e );
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Template.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for editing templates
|
||||
*/
|
||||
function TemplateEditController($scope, $http, assetsService, templateResource, $routeParams, $log) {
|
||||
|
||||
$scope.pageId = 1069;
|
||||
|
||||
$scope.rendering = false;
|
||||
$scope.aceLoaded = function(_editor) {
|
||||
// Options
|
||||
};
|
||||
|
||||
var render = _.throttle(function(){
|
||||
templateResource.saveAndRender($scope.template.content, $scope.template.id, $scope.pageId).then(
|
||||
function(response){
|
||||
var iframe = document.getElementById('mockingbird');
|
||||
iframe = (iframe.contentWindow) ? iframe.contentWindow : (iframe.contentDocument.document) ? iframe.contentDocument.document : iframe.contentDocument;
|
||||
iframe.document.open();
|
||||
iframe.document.write(response);
|
||||
iframe.document.close();
|
||||
$scope.rendering = false;
|
||||
},
|
||||
function(response){
|
||||
$log.log(response);
|
||||
$scope.rendering = false;
|
||||
}
|
||||
);
|
||||
|
||||
}, 1000);
|
||||
|
||||
$scope.aceChanged = function(e) {
|
||||
if(!$scope.rendering){
|
||||
$scope.rendering = true;
|
||||
render();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
templateResource.getById($routeParams.id).then(function(template){
|
||||
$scope.template = template;
|
||||
if(!$scope.rendering){
|
||||
$scope.rendering = true;
|
||||
render();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Template.EditController", TemplateEditController);
|
||||
@@ -0,0 +1,26 @@
|
||||
<div ng-form name="contentForm" val-form-manager>
|
||||
<umb-panel ng-controller="Umbraco.Editors.Template.EditController">
|
||||
|
||||
<umb-header>
|
||||
<h1>{{template.name}}</h1>
|
||||
</umb-header>
|
||||
|
||||
<div class="umb-panel-body umb-scrollable row-fluid">
|
||||
<div class="span6" style="position: relative; height: 100%">
|
||||
|
||||
<div style="width: 100%; height: 100%; top: 0; bottom: 0; position: absolute" ng-model="template.content" ui-ace="{
|
||||
useWrapMode : true,
|
||||
showGutter: true,
|
||||
theme:'twilight',
|
||||
mode: 'xml',
|
||||
onLoad: aceLoaded,
|
||||
onChange: aceChanged
|
||||
}"></div>
|
||||
</div>
|
||||
<div class="span6" style="position: relative; height: 100%">
|
||||
<iframe id="mockingbird" style="width: 100%; height: 100%; top: 0; bottom: 0; position: absolute" id="preview" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</umb-panel>
|
||||
</div>
|
||||
@@ -1,13 +0,0 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Settings.Template.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for editing templates
|
||||
*/
|
||||
function TemplateEditController($scope, navigationService) {
|
||||
$scope.template = "<html><body><h1>Hej</h1></body></html>";
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Settings.Template.EditController", TemplateEditController);
|
||||
@@ -1,19 +0,0 @@
|
||||
<div ng-form name="contentForm" val-form-manager>
|
||||
<umb-panel ng-controller="Umbraco.Editors.Settings.Template.EditController">
|
||||
<umb-header>
|
||||
<h1>woop</h1>
|
||||
</umb-header>
|
||||
|
||||
<div class="umb-pane row-fluid">
|
||||
<div class="span6">
|
||||
<div ace="html" ng-model="template">
|
||||
<textarea></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="span6">
|
||||
<iframe style="width: 100%; height: 100%" id="preview" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</umb-panel>
|
||||
</div>
|
||||
@@ -2075,6 +2075,7 @@
|
||||
<Content Include="Web.config">
|
||||
<SubType>Designer</SubType>
|
||||
</Content>
|
||||
<Content Include="Views\Partials\Grid\bootstrap3.cshtml" />
|
||||
<None Include="Web.Debug.config.transformed" />
|
||||
<None Include="web.Template.Debug.config">
|
||||
<DependentUpon>Web.Template.config</DependentUpon>
|
||||
@@ -2505,11 +2506,11 @@
|
||||
<Folder Include="Media\" />
|
||||
<Folder Include="Scripts\" />
|
||||
<Folder Include="Umbraco\PartialViews\Templates\" />
|
||||
<Folder Include="Umbraco\preview\" />
|
||||
<Folder Include="Umbraco_Client\FolderBrowser\Images\" />
|
||||
<Folder Include="Umbraco_Client\Tags\images\" />
|
||||
<Folder Include="UserControls\" />
|
||||
<Folder Include="Views\MacroPartials\" />
|
||||
<Folder Include="Views\Partials\" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
@@ -2530,9 +2531,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7150</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7200</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7150</IISUrl>
|
||||
<IISUrl>http://localhost:7200</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -0,0 +1,238 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link href="/Umbraco/lib/bootstrap/css/bootstrap.min.3.0.1.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/assets/css/tuning.panelStyles.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/spectrum/spectrum.css" type="text/css" rel="stylesheet" />
|
||||
<link href="/Umbraco/lib/jquery/jquery-ui-1.10.4.custom.min.css" type="text/css" rel="stylesheet" />
|
||||
</head>
|
||||
|
||||
<body id="tuningPanel" ng-class="{open:isOpen}" ng-controller="Umbraco.tuningController">
|
||||
|
||||
<div class="wait" ng-show="!frameLoaded">Loading ...</div>
|
||||
|
||||
<div id="demo-iframe-wrapper" ng-show="frameLoaded" class="{{previewDevice.css}}">
|
||||
<iframe id="resultFrame" ng-src="{{pageId}}" frameborder="0"></iframe>
|
||||
</div>
|
||||
|
||||
<div class="tuning">
|
||||
|
||||
<div id="TuningBg" ng-class="{open:isOpen}" style="display: block;">
|
||||
|
||||
<div class="tuning-tools">
|
||||
|
||||
<div ng-click="togglePanel()">
|
||||
<i ng-if="isOpen" class="icon icon-left-double-arrow"></i>
|
||||
<i ng-if="!isOpen" class="icon icon-right-double-arrow"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('previewDevice')" ng-class="{selected:settingIsOpen=='previewDevice', show:frameLoaded}" style="display:none">
|
||||
<i class="icon icon-display"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('setting')" ng-class="{selected:settingIsOpen=='setting', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-paint-roller"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="isOpen" ng-click="settingOpen('presetColors')" ng-class="{selected:settingIsOpen=='presetColors', show:enableTuning > 0}" style="display:none">
|
||||
<i class="icon icon-palette"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="tuning-wrapper">
|
||||
|
||||
<div ng-show="settingIsOpen == 'previewDevice'">
|
||||
|
||||
<h2>DEVICES</h2>
|
||||
<ul class="preview-device">
|
||||
<li ng-repeat="device in devices" ng-class=" { selected:previewDevice==device }" ng-click="updatePreviewDevice(device)">
|
||||
<div><i class="icon {{device.icon}}"></i><span>{{device.name}}</span></div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'setting'">
|
||||
|
||||
<tabset vertical="false">
|
||||
|
||||
<tab ng-repeat="category in tuningModel.categories" active="category.active">
|
||||
|
||||
<tab-heading>
|
||||
<span>{{category.name}}</span>
|
||||
</tab-heading>
|
||||
|
||||
<div ng-repeat="section in category.sections">
|
||||
|
||||
<accordion close-others="true">
|
||||
|
||||
<accordion-group ng-repeat="subSection in section.subSections"
|
||||
ng-class="{true:'selected', false:''}[isOpen]"
|
||||
is-open="(schemaFocus != '' && schemaFocus == subSection.name.toLowerCase())">
|
||||
|
||||
<accordion-heading>
|
||||
<span ng-click="accordionOpened(subSection.name)" ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
{{subSection.name}}
|
||||
</span>
|
||||
</accordion-heading>
|
||||
|
||||
<div ng-mouseover="accordionWillBeOpened(subSection.schema)">
|
||||
<div class="div-field" ng-repeat="field in subSection.fields">
|
||||
|
||||
<span class="field-title">{{field.name}}:</span>
|
||||
|
||||
<div ng-if="field.type == 'colorPicker'">
|
||||
<spectrum colorselected="field.value"></spectrum>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgImagePicker'" class="imagePickerPreviewContainer">
|
||||
<div class="imagePickerPreview" ng-click="open(field)" style="background-image:{{ field.value }}">
|
||||
<i class="icon icon-add"></i>
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="icon icon-delete colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgPositionPicker'">
|
||||
<select ng-options="BackgroundPosition for BackgroundPosition in BackgroundPositions" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgRepeatPicker'">
|
||||
<select ng-options="BackgroundRepeat for BackgroundRepeat in BackgroundRepeats" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'bgAttachmentPicker'">
|
||||
<select ng-options="BackgroundAttachment for BackgroundAttachment in BackgroundAttachments" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'layoutPicker'">
|
||||
<select ng-options="Layout for Layout in Layouts" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div class="box-slider" ng-if="field.type == 'slider'">
|
||||
<div ui-slider min="{{field.min}}" max="{{field.max}}" step="1" ng-model="field.value"></div>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'checkbox'">
|
||||
<input type="checkbox" ng-checked="field.value == 'true'" ng-model="field.value">
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'displayPicker'">
|
||||
<select ng-options="display for display in displays" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'optionHomePicker'">
|
||||
<select ng-options="optionHome for optionHome in optionHomes" ng-model="field.value"></select>
|
||||
</div>
|
||||
|
||||
<div ng-if="field.type == 'fontFamilyPicker'">
|
||||
<div class="fontFamilyPickerPreview" ng-click="openFontFamilyPickerModal(field)" style="font-family:{{ field.value }}">
|
||||
<span>Aa</span>
|
||||
{{ field.value }}
|
||||
</div>
|
||||
<i ng-if="field.value != ''" ng-click="removeField(field)" class="fa fa-times colorPickerDelete"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</accordion-group>
|
||||
</accordion>
|
||||
|
||||
</div>
|
||||
|
||||
</tab>
|
||||
|
||||
</tabset>
|
||||
|
||||
<button class="btn btn-default btn-default-save" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-delete" ng-click="deleteTuning()">reset</button>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-show="settingIsOpen == 'presetColors'">
|
||||
|
||||
<h2>PALETTE COLORS</h2>
|
||||
<ul class="palette">
|
||||
<li ng-click="refreshtuningByPalette(palette)" ng-repeat="palette in tuningPalette">
|
||||
<div>
|
||||
<span style="background-color: {{ palette.mainColor }}"></span>
|
||||
</div>
|
||||
<p>{{ palette.name }}</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<button class="btn btn-default btn-default-save" style="display:none" ng-click="saveLessParameters()">save</button>
|
||||
<button class="btn btn-default btn-default-save" ng-click="makePreset()">make it !</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/ng-template" id="myModalContent.html">
|
||||
<div class="modal-header bodyTuningImagePicker ng-scope">
|
||||
<ul class="breadcrumb">
|
||||
<li ng-if="startNodeId == -1">
|
||||
<a href="" ng-click="gotoFolder()">Media</a>
|
||||
</li>
|
||||
|
||||
<!-- ngRepeat: item in path -->
|
||||
<li ng-repeat="item in currentPath" class="ng-scope">
|
||||
<a ng-if="currentFolder.id == item.id" href="" ng-class="{disabled:currentFolder.id == item.id}">{{ item.name }}</a>
|
||||
<a ng-if="currentFolder.id != item.id" ng-click="gotoFolder(item)">{{ item.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-body bodyTuningImagePicker">
|
||||
<ul class="tuningImagePicker">
|
||||
<li>
|
||||
<ul class="media-items">
|
||||
<li ng-repeat="child in currentFolder.children | orderBy:'isFolder':true">
|
||||
<div ng-if="!child.isFolder" class=" media-preview" ng-class="{selected:selectedMedia.id == child.id}" ng-click="selectMedia(child)" style="background-image: url({{ child.thumbnail }})"></div>
|
||||
<div ng-if="child.isFolder" class=" media-preview" ng-click="selectMedia(child)">
|
||||
<i class="icon icon-folder folder"><p class="folder-name">{{child.name}}</p></i>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/ng-template" id="fontFamilyPickerModel.html">
|
||||
|
||||
<div class="modal-header tuning-fontfamilypicker">
|
||||
<select ng-model="selectedFont" ng-change="showFontPreview(selectedFont)" ng-options="font as font.fontFamily group by font.fontType for font in fonts"></select>
|
||||
<select ng-model="selectedFont.variant" ng-change="showFontPreview(selectedFont)" ng-options="variant for variant in selectedFont.variants" />
|
||||
</div>
|
||||
|
||||
<div class="modal-body tuning-fontfamilypicker">
|
||||
<span class="show" ng-style="setStyleVariant()">Aa Bb Cc 1 2 3 4… <br />The quick brown fox jumps over the lazy dog…</span>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer tuning-fontfamilypicker">
|
||||
<button class="btn btn-primary" ng-click="ok()">OK</button>
|
||||
<button class="btn btn-warning" ng-click="cancel()">Cancel</button>
|
||||
</div>
|
||||
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="speechbubble">
|
||||
<p>Styles saved and visible at the website</p>
|
||||
</div>
|
||||
|
||||
<script src="/umbraco/lib/lazyload/lazyload.min.js"></script>
|
||||
<script src="/umbraco/js/tuning.loader.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,111 @@
|
||||
@inherits UmbracoViewPage<dynamic>
|
||||
@using Umbraco.Web.Templates
|
||||
|
||||
|
||||
@if (Model != null && !string.IsNullOrEmpty(Model.ToString()))
|
||||
{
|
||||
var onlyOneColumn = Model.columns != null ? ((System.Collections.ICollection)Model.columns).Count : 0;
|
||||
|
||||
<div class="uSky-grid @(onlyOneColumn > 1 ? "container" : "")">
|
||||
<div class="row clearfix">
|
||||
@foreach (var column in Model.columns)
|
||||
{
|
||||
<div class="col-md-@column.grid column">
|
||||
@foreach (var row in column.rows)
|
||||
{
|
||||
<div class="gridrow_@row.uniqueId" >
|
||||
<div class="container">
|
||||
<div class="row clearfix">
|
||||
|
||||
@foreach (var cell in row.cells)
|
||||
{
|
||||
<div class="col-md-@cell.model.grid column">
|
||||
|
||||
@foreach (var control in cell.controls)
|
||||
{
|
||||
if (control != null && control.editor != null && control.editor.view != null)
|
||||
{
|
||||
|
||||
string editor = control.editor.view.ToString();
|
||||
|
||||
switch (editor)
|
||||
{
|
||||
case "rte":
|
||||
<text>
|
||||
@Html.Raw(TemplateUtilities.ParseInternalLinks(control.value.ToString()))
|
||||
</text>
|
||||
break;
|
||||
case "macro":
|
||||
if (control.value != null)
|
||||
{
|
||||
string macroAlias = control.value.macroAlias.ToString();
|
||||
ViewDataDictionary parameters = new ViewDataDictionary();
|
||||
foreach (dynamic mpd in control.value.marcoParamsDictionary)
|
||||
{
|
||||
parameters.Add(mpd.Name, mpd.Value);
|
||||
}
|
||||
|
||||
<text>
|
||||
@Umbraco.RenderMacro(macroAlias, parameters)
|
||||
</text>
|
||||
}
|
||||
break;
|
||||
case "textstring":
|
||||
|
||||
if (control.editor.config.markup != null)
|
||||
{
|
||||
string markup = control.editor.config.markup.ToString();
|
||||
|
||||
markup = markup.Replace("#value#", control.value.ToString());
|
||||
markup = markup.Replace("#style#", control.editor.config.style.ToString());
|
||||
|
||||
<text>
|
||||
@Html.Raw(markup)
|
||||
</text>
|
||||
}
|
||||
else
|
||||
{
|
||||
<text>
|
||||
<div style="@control.editor.config.style">@control.value</div>
|
||||
</text>
|
||||
}
|
||||
|
||||
break;
|
||||
case "media":
|
||||
<text>
|
||||
@if (control.value != null)
|
||||
{
|
||||
<div class="thumbnail">
|
||||
<img src="@control.value.image">
|
||||
</div>
|
||||
if (control.value.caption != null)
|
||||
{
|
||||
<p class="caption">@control.value.caption</p>
|
||||
}
|
||||
}
|
||||
</text>
|
||||
break;
|
||||
case "embed":
|
||||
<text>
|
||||
@Html.Raw(control.value)
|
||||
</text>
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@@ -10,7 +10,7 @@ NOTES:
|
||||
* Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config
|
||||
* A new version will invalidate both client and server cache and create new persisted files
|
||||
-->
|
||||
<clientDependency version="1469612626" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
<clientDependency version="912222045" fileDependencyExtensions=".js,.css" loggerType="Umbraco.Web.UI.CdfLogger, umbraco">
|
||||
|
||||
<!--
|
||||
This section is used for Web Forms only, the enableCompositeFiles="true" is optional and by default is set to true.
|
||||
|
||||
@@ -39,4 +39,5 @@
|
||||
<!-- Custom -->
|
||||
<!--<add application="myApplication" alias="myTree" title="Me Tree" type="MyNamespace.myTree, MyAssembly"
|
||||
iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="10" />-->
|
||||
<add initialize="true" sortOrder="0" alias="template" application="settings" title="Templates" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.TemplateTreeController, umbraco" />
|
||||
</trees>
|
||||
@@ -29,7 +29,8 @@
|
||||
<PropertyContextHelpOption>text</PropertyContextHelpOption>
|
||||
|
||||
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
|
||||
<PreviewBadge><![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="{0}/endPreview.aspx?redir={2}"><span style="display:none;">In Preview Mode - click to end</span></a>]]></PreviewBadge>
|
||||
<PreviewBadge>
|
||||
<![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={2}'"><span style="display:none;">In Preview Mode - click to end</span></a>]]></PreviewBadge>
|
||||
|
||||
<!-- Cache cycle of Media and Member data fetched from the umbraco.library methods -->
|
||||
<!-- In seconds. 0 will disable cache -->
|
||||
|
||||
@@ -76,7 +76,9 @@
|
||||
<PropertyContextHelpOption>text</PropertyContextHelpOption>
|
||||
|
||||
<!-- The html injected into a (x)html page if Umbraco is running in preview mode -->
|
||||
<PreviewBadge><![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="{0}/endPreview.aspx?redir={2}"><span style="display:none;">In Preview Mode - click to end</span></a>]]></PreviewBadge>
|
||||
<PreviewBadge>
|
||||
<![CDATA[<a id="umbracoPreviewBadge" style="position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{1}/preview/previewModeBadge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/endPreview.aspx?redir={2}'"><span style="display:none;">In Preview Mode - click to end</span></a>
|
||||
]]></PreviewBadge>
|
||||
|
||||
<!-- Cache cycle of Media and Member data fetched from the umbraco.library methods -->
|
||||
<!-- In seconds. 0 will disable cache -->
|
||||
|
||||
@@ -245,6 +245,7 @@
|
||||
</area>
|
||||
<area alias="editcontenttype">
|
||||
<key alias="allowedchildnodetypes">Allowed child node types</key>
|
||||
<key alias="contenttypecompositions">Document Type Compositions</key>
|
||||
<key alias="create">Create</key>
|
||||
<key alias="deletetab">Delete tab</key>
|
||||
<key alias="description">Description</key>
|
||||
|
||||
@@ -251,6 +251,7 @@
|
||||
|
||||
<area alias="editcontenttype">
|
||||
<key alias="allowedchildnodetypes">Allowed child nodetypes</key>
|
||||
<key alias="contenttypecompositions">Document Type Compositions</key>
|
||||
<key alias="create">Create</key>
|
||||
<key alias="deletetab">Delete tab</key>
|
||||
<key alias="description">Description</key>
|
||||
|
||||
@@ -81,13 +81,20 @@
|
||||
<asp:CheckBox runat="server" ID="cb_isContainer" Text="Yes" /><br />
|
||||
</cc2:PropertyPanel>
|
||||
</cc2:Pane>
|
||||
<cc2:Pane ID="Pane5" runat="server">
|
||||
|
||||
<cc2:PropertyPanel ID="pp_allowedChildren" runat="server" Text="Allowed Child nodetypes">
|
||||
<asp:CheckBoxList ID="lstAllowedContentTypes" runat="server" EnableViewState="True"/>
|
||||
<asp:PlaceHolder ID="PlaceHolderAllowedContentTypes" runat="server"/>
|
||||
</cc2:PropertyPanel>
|
||||
</cc2:Pane>
|
||||
|
||||
<cc2:Pane ID="Pane5" runat="server">
|
||||
<cc2:PropertyPanel ID="pp_allowedChildren" runat="server" Text="Allowed Child nodetypes">
|
||||
<asp:CheckBoxList ID="lstAllowedContentTypes" runat="server" EnableViewState="True"/>
|
||||
<asp:PlaceHolder ID="PlaceHolderAllowedContentTypes" runat="server"/>
|
||||
</cc2:PropertyPanel>
|
||||
</cc2:Pane>
|
||||
|
||||
<cc2:Pane ID="Pane9" runat="server">
|
||||
<cc2:PropertyPanel ID="pp_compositions" runat="server" Text="ContentType Compositions">
|
||||
<asp:CheckBoxList ID="lstContentTypeCompositions" runat="server" EnableViewState="True"/>
|
||||
<asp:PlaceHolder ID="PlaceHolderContentTypeCompositions" runat="server"/>
|
||||
</cc2:PropertyPanel>
|
||||
</cc2:Pane>
|
||||
</asp:Panel>
|
||||
|
||||
|
||||
|
||||
@@ -202,7 +202,12 @@ namespace Umbraco.Web.UI.Umbraco.Settings.Views
|
||||
ClientCallbackOpenMacroModel = "function(alias) {editViewEditor.openMacroModal(alias);}"
|
||||
};
|
||||
editorSource.Menu.InsertNewControl(macroSplitButton, 40);
|
||||
|
||||
|
||||
MenuIconI umbTemplateQueryBuilder = editorSource.Menu.NewIcon();
|
||||
umbTemplateQueryBuilder.ImageURL = UmbracoPath + "/images/editor/inshtml.gif";
|
||||
umbTemplateQueryBuilder.OnClickCommand = "editViewEditor.openQueryModal()";
|
||||
umbTemplateQueryBuilder.AltText = "Open query builder";
|
||||
|
||||
if (_template == null)
|
||||
{
|
||||
InitializeEditorForPartialView();
|
||||
|
||||
@@ -157,6 +157,18 @@ Umbraco.Sys.registerNamespace("Umbraco.Application");
|
||||
|
||||
},
|
||||
|
||||
/** This is used to launch an angular based modal window instead of the legacy window */
|
||||
rootScope: function () {
|
||||
|
||||
if (!this.mainWindow().UmbClientMgr) {
|
||||
throw "An angular modal window can only be launched when the modal is running within the main Umbraco application";
|
||||
}
|
||||
else {
|
||||
return this.mainWindow().UmbClientMgr.rootScope();
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
openModalWindow: function(url, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback) {
|
||||
//need to create the modal on the top window if the top window has a client manager, if not, create it on the current window
|
||||
|
||||
|
||||
@@ -69,6 +69,33 @@
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
openQueryModal: function () {
|
||||
/// <summary>callback used to display the modal dialog to insert a macro with parameters</summary>
|
||||
|
||||
var self = this;
|
||||
|
||||
UmbClientMgr.openAngularModalWindow({
|
||||
template: "views/common/dialogs/template/queryBuilder.html",
|
||||
callback: function (data) {
|
||||
|
||||
//var dataFormatted = data.replace(new RegExp('[' + "." + ']', 'g'), "\n\t\t\t\t\t.");
|
||||
|
||||
var code = "\n@{\n" + "\tvar selection = " + data + ";\n}\n";
|
||||
code += "<ul>\n" +
|
||||
"\t@foreach(var item in selection){\n" +
|
||||
"\t\t<li>\n" +
|
||||
"\t\t\t<a href=\"@item.Url\">@item.Name</a>\n" +
|
||||
"\t\t</li>\n" +
|
||||
"\t}\n" +
|
||||
"</ul>\n\n";
|
||||
|
||||
UmbEditor.Insert(code, '', self._opts.codeEditorElementId);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
doSubmit: function () {
|
||||
/// <summary>Submits the data to the server for saving</summary>
|
||||
var codeVal = UmbClientMgr.contentFrame().UmbEditor.GetCode();
|
||||
|
||||
@@ -195,6 +195,8 @@
|
||||
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
|
||||
<remove fileExtension=".woff"/>
|
||||
<mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
|
||||
<remove fileExtension=".less" />
|
||||
<mimeMap fileExtension=".less" mimeType="text/css" />
|
||||
</staticContent>
|
||||
|
||||
<!-- Ensure the powered by header is not returned -->
|
||||
|
||||
@@ -185,6 +185,10 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
"stylesheetApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<StylesheetController>(
|
||||
controller => controller.GetAll())
|
||||
},
|
||||
{
|
||||
"templateApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TemplateController>(
|
||||
controller => controller.GetById(0))
|
||||
},
|
||||
{
|
||||
"memberTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MemberTypeController>(
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
using AutoMapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
|
||||
public class TemplateController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the content json for the content id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
public TemplateDisplay GetById(int id)
|
||||
{
|
||||
var template = Services.FileService.GetTemplate(id);
|
||||
if (template == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
TemplateDisplay t = new TemplateDisplay();
|
||||
t.Alias = template.Alias;
|
||||
t.Content = template.Content;
|
||||
t.Id = template.Id;
|
||||
t.Name = template.Name;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a data type wth a given ID
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public HttpResponseMessage DeleteById(int id)
|
||||
{
|
||||
var foundTemplate = Services.FileService.GetTemplate(id);
|
||||
if (foundTemplate == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
Services.FileService.DeleteTemplate(foundTemplate.Alias);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public HttpResponseMessage PostSaveAndRender(dynamic model)
|
||||
{
|
||||
var foundTemplate = Services.FileService.GetTemplate((int)model.templateId);
|
||||
if (foundTemplate == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
foundTemplate.Content = model.html;
|
||||
Services.FileService.SaveTemplate(foundTemplate);
|
||||
|
||||
string result = string.Empty;
|
||||
try
|
||||
{
|
||||
var url = "http://" + Request.RequestUri.Host + "/" + model.pageId + ".aspx?altTemplate=" + foundTemplate.Alias;
|
||||
result = url;
|
||||
|
||||
WebClient wc = new WebClient();
|
||||
result = wc.DownloadString(new Uri(url));
|
||||
}
|
||||
catch (WebException exception)
|
||||
{
|
||||
if (exception.Response != null)
|
||||
{
|
||||
var responseStream = exception.Response.GetResponseStream();
|
||||
|
||||
if (responseStream != null)
|
||||
{
|
||||
using (var reader = new StreamReader(responseStream))
|
||||
{
|
||||
result = reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result += ex.ToString();
|
||||
}
|
||||
|
||||
|
||||
return new HttpResponseMessage()
|
||||
{
|
||||
Content = new StringContent(
|
||||
result,
|
||||
Encoding.UTF8,
|
||||
"text/html"
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Editors.TemplateQuery
|
||||
{
|
||||
public class ContentTypeModel
|
||||
{
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
public enum Operathor
|
||||
{
|
||||
Equals = 1,
|
||||
NotEquals = 2,
|
||||
Contains = 3,
|
||||
NotContains = 4,
|
||||
LessThan = 5,
|
||||
LessThanEqualTo = 6,
|
||||
GreaterThan = 7,
|
||||
GreaterThanEqualTo = 8
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
public class OperathorTerm
|
||||
{
|
||||
public OperathorTerm()
|
||||
{
|
||||
Name = "is";
|
||||
Operathor = Operathor.Equals;
|
||||
AppliesTo = new [] { "string" };
|
||||
}
|
||||
|
||||
public OperathorTerm(string name, Operathor operathor, IEnumerable<string> appliesTo)
|
||||
{
|
||||
Name = name;
|
||||
Operathor = operathor;
|
||||
AppliesTo = appliesTo;
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public Operathor Operathor { get; set; }
|
||||
public IEnumerable<string> AppliesTo { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Editors.TemplateQuery
|
||||
{
|
||||
public class PropertyModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Alias { get; set; }
|
||||
|
||||
public string Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
using Umbraco.Web.Editors.TemplateQuery;
|
||||
|
||||
public class QueryCondition
|
||||
{
|
||||
|
||||
public PropertyModel Property { get; set; }
|
||||
public OperathorTerm Term { get; set; }
|
||||
public string ConstraintValue { get; set; }
|
||||
}
|
||||
|
||||
|
||||
internal static class QueryConditionExtensions
|
||||
{
|
||||
private static string MakeBinaryOperation(this QueryCondition condition, string operand, int token)
|
||||
{
|
||||
return string.Format("{0}{1}@{2}", condition.Property.Name, operand, token);
|
||||
}
|
||||
|
||||
|
||||
public static string BuildCondition(this QueryCondition condition, int token)
|
||||
{
|
||||
var operand = string.Empty;
|
||||
var value = string.Empty;
|
||||
|
||||
switch (condition.Term.Operathor)
|
||||
{
|
||||
case Operathor.Equals:
|
||||
operand = " == ";
|
||||
break;
|
||||
case Operathor.NotEquals:
|
||||
operand = " != ";
|
||||
break;
|
||||
case Operathor.GreaterThan:
|
||||
operand = " > ";
|
||||
break;
|
||||
case Operathor.GreaterThanEqualTo:
|
||||
operand = " >= ";
|
||||
break;
|
||||
case Operathor.LessThan:
|
||||
operand = " < ";
|
||||
break;
|
||||
case Operathor.LessThanEqualTo:
|
||||
operand = " <= ";
|
||||
break;
|
||||
case Operathor.Contains:
|
||||
value = string.Format("{0}.Contains(@{1})", condition.Property.Name, token);
|
||||
break;
|
||||
case Operathor.NotContains:
|
||||
value = string.Format("!{0}.Contains(@{1})", condition.Property.Name, token);
|
||||
break;
|
||||
default :
|
||||
operand = " == ";
|
||||
break;
|
||||
}
|
||||
|
||||
return string.IsNullOrEmpty(value) ? condition.MakeBinaryOperation(operand, token) : value;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
using Umbraco.Web.Editors.TemplateQuery;
|
||||
|
||||
public class QueryModel
|
||||
{
|
||||
public ContentTypeModel ContentType { get; set; }
|
||||
public SourceModel Source { get; set; }
|
||||
public IEnumerable<QueryCondition> Filters { get; set; }
|
||||
public SortExpression Sort { get; set; }
|
||||
public int Take { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
|
||||
public class QueryResultModel
|
||||
{
|
||||
|
||||
public string QueryExpression { get; set; }
|
||||
public IEnumerable<TemplateQueryResult> SampleResults { get; set; }
|
||||
public int ResultCount { get; set; }
|
||||
public double ExecutionTime { get; set; }
|
||||
public int Take { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
using Umbraco.Web.Editors.TemplateQuery;
|
||||
|
||||
public class SortExpression
|
||||
{
|
||||
public PropertyModel Property { get; set; }
|
||||
|
||||
public string Direction { get; set; }
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user