merge content/edit.html

This commit is contained in:
perploug
2013-08-16 13:29:23 +02:00
parent ddccc378d5
commit a82c367db8
16 changed files with 454 additions and 83 deletions

View File

@@ -0,0 +1,28 @@
/**
* @ngdoc directive
* @name umbraco.directives.directive:headline
**/
angular.module("umbraco.directives")
.directive('hotkey', function ($window, keyboardService, $log) {
return function (scope, el, attrs) {
var keyCombo = attrs["hotkey"];
$log.log(keyCombo);
keyboardService.bind(keyCombo, function() {
var element = $(el);
$log.log(element);
if(element.is("a,button,input[type='button'],input[type='submit']")){
element.click();
$log.log("click");
}else{
element.focus();
$log.log("focus");
}
});
};
});

View File

@@ -73,6 +73,7 @@ angular.module('umbraco.services')
var $modal = $('<div data-backdrop="false"></div>');
var id = templateUrl.replace('.html', '').replace('.aspx', '').replace(/[\/|\.|:\&\?\=]/g, "-") + '-' + scope.$id;
if(options.inline){
animationClass = "";
@@ -137,6 +138,8 @@ angular.module('umbraco.services')
$compile($modal)(scope);
});
scope.dialogOptions = options;
//Scope to handle data from the modal form
scope.dialogData = {};
scope.dialogData.selection = [];
@@ -270,7 +273,7 @@ angular.module('umbraco.services')
*/
mediaPicker: function (options) {
return openDialog({
scope: options.scope,
scope: options.scope,
callback: options.callback,
template: 'views/common/dialogs/mediaPicker.html',
show: true
@@ -286,6 +289,7 @@ angular.module('umbraco.services')
* Opens a content picker tree in a modal, the callback returns an array of selected documents
* @param {Object} options content picker dialog options object
* @param {$scope} options.scope dialog scope
* @param {$scope} options.multipicker should the picker return one or multiple items
* @param {Function} options.callback callback function
* @returns {Object} modal object
*/
@@ -293,6 +297,7 @@ angular.module('umbraco.services')
return openDialog({
scope: options.scope,
callback: options.callback,
multipicker: options.multipicker,
template: 'views/common/dialogs/contentPicker.html',
show: true
});

View File

@@ -0,0 +1,261 @@
// This service was based on OpenJS library available in BSD License
// http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php
angular.module('umbraco.services')
.factory('keyboardService', ['$window', '$timeout', function ($window, $timeout) {
var keyboardManagerService = {};
var defaultOpt = {
'type': 'keydown',
'propagate': false,
'inputDisabled': false,
'target': $window.document,
'keyCode': false
};
// Store all keyboard combination shortcuts
keyboardManagerService.keyboardEvent = {};
// Add a new keyboard combination shortcut
keyboardManagerService.bind = function (label, callback, opt) {
var fct, elt, code, k;
// Initialize opt object
opt = angular.extend({}, defaultOpt, opt);
label = label.toLowerCase();
elt = opt.target;
if(typeof opt.target === 'string'){
elt = document.getElementById(opt.target);
}
fct = function (e) {
e = e || $window.event;
// Disable event handler when focus input and textarea
if (opt['inputDisabled']) {
var elt;
if (e.target){
elt = e.target;
}else if (e.srcElement){
elt = e.srcElement;
}
if (elt.nodeType === 3){elt = elt.parentNode;}
if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA'){return;}
}
// Find out which key is pressed
if (e.keyCode){
code = e.keyCode;
}else if (e.which){
code = e.which;
}
var character = String.fromCharCode(code).toLowerCase();
if (code === 188){character = ",";} // If the user presses , when the type is onkeydown
if (code === 190){character = ".";} // If the user presses , when the type is onkeydown
var keys = label.split("+");
// Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
// Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
};
// Special Keys - and their codes
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
'pause':19,
'break':19,
'insert':45,
'home':36,
'delete':46,
'end':35,
'pageup':33,
'page_up':33,
'pu':33,
'pagedown':34,
'page_down':34,
'pd':34,
'left':37,
'up':38,
'right':39,
'down':40,
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
};
// Some modifiers key
var modifiers = {
shift: {
wanted: false,
pressed: e.shiftKey ? true : false
},
ctrl : {
wanted: false,
pressed: e.ctrlKey ? true : false
},
alt : {
wanted: false,
pressed: e.altKey ? true : false
},
meta : { //Meta is Mac specific
wanted: false,
pressed: e.metaKey ? true : false
}
};
// Foreach keys in label (split on +)
var l = keys.length;
for (var i = 0; i < l; i++) {
var k=keys[i];
switch (k) {
case 'ctrl':
case 'control':
kp++;
modifiers.ctrl.wanted = true;
break;
case 'shift':
case 'alt':
case 'meta':
kp++;
modifiers[k].wanted = true;
break;
}
if (k.length > 1) { // If it is a special key
if(special_keys[k] === code){
kp++;
}
} else if (opt['keyCode']) { // If a specific key is set into the config
if (opt['keyCode'] === code) {
kp++;
}
} else { // The special keys did not match
if(character === k) {
kp++;
}else {
if(shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if(character === k){
kp++;
}
}
}
}
} //for end
if(kp === keys.length &&
modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
modifiers.shift.pressed === modifiers.shift.wanted &&
modifiers.alt.pressed === modifiers.alt.wanted &&
modifiers.meta.pressed === modifiers.meta.wanted) {
$timeout(function() {
callback(e);
}, 1);
if(!opt['propagate']) { // Stop the event
// e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
// e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
};
// Store shortcut
keyboardManagerService.keyboardEvent[label] = {
'callback': fct,
'target': elt,
'event': opt['type']
};
//Attach the function with the event
if(elt.addEventListener){
elt.addEventListener(opt['type'], fct, false);
}else if(elt.attachEvent){
elt.attachEvent('on' + opt['type'], fct);
}else{
elt['on' + opt['type']] = fct;
}
};
// Remove the shortcut - just specify the shortcut and I will remove the binding
keyboardManagerService.unbind = function (label) {
label = label.toLowerCase();
var binding = keyboardManagerService.keyboardEvent[label];
delete(keyboardManagerService.keyboardEvent[label]);
if(!binding){return;}
var type = binding['event'],
elt = binding['target'],
callback = binding['callback'];
if(elt.detachEvent){
elt.detachEvent('on' + type, callback);
}else if(elt.removeEventListener){
elt.removeEventListener(type, callback, false);
}else{
elt['on'+type] = false;
}
};
//
return keyboardManagerService;
}]);

View File

@@ -23,6 +23,7 @@
@import "../../lib/bootstrap/less/type.less";
@import "../../lib/bootstrap/less/code.less";
@import "tables.less";
@import "colors.less";
// Components: common
@import "../../lib/bootstrap/less/sprites.less";

View File

@@ -0,0 +1 @@
i.red{color: #b94a48;}

View File

@@ -7,11 +7,16 @@
.hideLabel label {
display: none;
}
.hideLabel .controls-row {
margin-left: 0px !Important;
}
//utill styll to hide child untill hover
.hover-show{visibility: hidden;}
*:hover > .hover-show{visibility: visible;}
// GENERAL STYLES
// --------------
@@ -45,6 +50,8 @@ legend {
}
}
// Set font for forms
label,
input,

View File

@@ -1,15 +1,28 @@
//used for the media picker dialog
angular.module("umbraco").controller("Umbraco.Dialogs.ContentPickerController",
function ($scope, eventsService) {
function ($scope, eventsService, $log) {
var dialogOptions = $scope.$parent.dialogOptions;
$scope.dialogTreeEventHandler = $({});
$log.log($scope);
$scope.dialogTreeEventHandler.bind("treeNodeSelect", function(ev, args){
args.event.preventDefault();
args.event.stopPropagation();
eventsService.publish("Umbraco.Dialogs.ContentPickerController.Select", args, "hello").then(function(args){
$(args.event.target.parentElement).find("i.umb-tree-icon").attr("class", "icon umb-tree-icon sprTree icon-check blue");
$scope.select(args.node);
});
if(dialogOptions && dialogOptions.multipicker){
$(args.event.target.parentElement)
.find("i.umb-tree-icon")
.attr("class", "icon umb-tree-icon sprTree icon-check blue");
$scope.select(args.node);
}else{
$scope.submit(args.node);
}
});
});
});

View File

@@ -9,13 +9,18 @@
*
* @param {navigationService} navigationService A reference to the navigationService
*/
function NavigationController($scope,$rootScope, $location, $log, navigationService, dialogService, historyService, sectionResource, angularHelper) {
function NavigationController($scope,$rootScope, $location, $log, navigationService, keyboardService, dialogService, historyService, sectionResource, angularHelper) {
//Put the navigation service on this scope so we can use it's methods/properties in the view.
// IMPORTANT: all properties assigned to this scope are generally available on the scope object on dialogs since
// when we create a dialog we pass in this scope to be used for the dialog's scope instead of creating a new one.
$scope.nav = navigationService;
//trigger search with a hotkey:
keyboardService.bind("ctrl+shift+s", function(){
$scope.nav.showTree($scope.ui.currentSection);
});
//the tree event handler i used to subscribe to the main tree click events
$scope.treeEventHandler = $({});

View File

@@ -7,7 +7,7 @@
<ul class="umb-actions-child">
<li ng-repeat="docType in allowedTypes">
<a href="#content/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="nav.hideNavigation()">
<a href="#content/content/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="nav.hideNavigation()">
<i class="icon-large {{docType.cssClass}}" style="{{docType.style}}"></i>
<span class="menu-label">
{{docType.name}}

View File

@@ -1,52 +1,52 @@
<form novalidate name="contentForm" ng-show="loaded" ng-submit="save(content)">
<umb-panel ng-controller="Umbraco.Editors.Content.EditController" val-show-validation>
<umb-header tabs="content.tabs">
<umb-content-name
ng-model="content.name"
placeholder="Enter a page title">
</umb-content-name>
<div class="span8">
<div class="btn-toolbar pull-right umb-btn-toolbar">
<div class="btn-group">
<a class="btn" ng-click="preview(content)"
data-shortcut="ctrl+s">Preview page</a>
</div>
<div class="btn-group">
<a class="btn btn-success" href="#" ng-click="saveAndPublish(content)" prevent-default data-shortcut="ctrl+p">Publish</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li>
<!--This should be changed to a submit button! but then we need to update the styles for dropdown-menu to support buttons -->
<a href="#" data-shortcut="ctrl+s" prevent-default ng-click="save(content)">Save draft</a>
</li>
</ul>
</div>
</div>
</div>
</umb-header>
<umb-tab-view>
<umb-tab id="tab{{tab.id}}" rel="{{tab.id}}" ng-repeat="tab in content.tabs">
<div class="umb-pane">
<umb-property
property="property"
ng-repeat="property in tab.properties">
<umb-editor model="property"></umb-editor>
</umb-property>
</div>
</umb-tab>
</umb-tab-view>
</umb-panel>
</form>
<form novalidate name="contentForm" ng-show="loaded" ng-submit="save(content)">
<umb-panel ng-controller="Umbraco.Editors.Content.EditController" val-show-validation>
<umb-header tabs="content.tabs">
<umb-content-name
ng-model="content.name"
placeholder="Enter a page title">
</umb-content-name>
<div class="span8">
<div class="btn-toolbar pull-right umb-btn-toolbar">
<div class="btn-group">
<a class="btn" ng-click="preview(content)">Preview page</a>
</div>
<div class="btn-group">
<a class="btn btn-success" href="#" ng-click="saveAndPublish(content)"
prevent-default data-hotkey="ctrl+p">Publish</a>
<a class="btn btn-success dropdown-toggle" data-toggle="dropdown">
<span class="caret"></span>
</a>
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li>
<!--This should be changed to a submit button! but then we need to update the styles for dropdown-menu to support buttons -->
<a href="#" data-hotkey="ctrl+s" prevent-default ng-click="save(content)">Save draft</a>
</li>
</ul>
</div>
</div>
</div>
</umb-header>
<umb-tab-view>
<umb-tab id="tab{{tab.id}}" rel="{{tab.id}}" ng-repeat="tab in content.tabs">
<div class="umb-pane">
<umb-property
property="property"
ng-repeat="property in tab.properties">
<umb-editor model="property"></umb-editor>
</umb-property>
</div>
</umb-tab>
</umb-tab-view>
</umb-panel>
</form>

View File

@@ -3,40 +3,56 @@
angular.module('umbraco')
.controller("Umbraco.Editors.ContentPickerController",
function($scope, dialogService, entityResource){
function($scope, dialogService, entityResource, $log, iconHelper){
$scope.ids = $scope.model.value.split(',');
$scope.renderModel = [];
$scope.multipicker = true;
entityResource.getByIds($scope.ids).then(function(data){
$(data).each(function(i, item){
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
});
});
$scope.openContentPicker =function(){
var d = dialogService.contentPicker({scope: $scope, callback: populate});
var d = dialogService.contentPicker({scope: $scope, multipicker: $scope.multipicker, callback: populate});
};
$scope.remove =function(index){
$scope.renderModel.splice(index, 1);
$scope.ids.splice(index, 1);
$scope.model.value = $scope.ids.join();
$scope.model.value = trim($scope.ids.join(), ",");
};
$scope.add =function(item){
if($scope.ids.indexOf(item.id) < 0){
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon})
$scope.ids.push(item.id);
$scope.model.value = $scope.ids.join();
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
$scope.ids.push(item.id);
$scope.model.value = trim($scope.ids.join(), ",");
}
};
$scope.clear = function(){
$scope.ids = [];
$scope.model.value = "";
$scope.renderModel = [];
}
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
return str.replace(rgxtrim, '');
}
function populate(data){
$(data.selection).each(function(i, item){
$scope.add(item);
});
if(data.selection && angular.isArray(data.selection)){
$(data.selection).each(function(i, item){
$scope.add(item);
});
}else{
$scope.clear();
$scope.add(data);
}
}
});

View File

@@ -1,11 +1,9 @@
<div ng-controller="Umbraco.Editors.ContentPickerController">
{{model | json }}
<ul class="nav nav-stacked">
<ul class="nav nav-stacked" style="width: 250px">
<li ng-repeat="node in renderModel">
<a href="#" prevent-default ng-click="remove($index)">
<i class="icon umb-tree-icon sprTree {{node.icon}}"></i>
<i class="icon icon-remove red hover-show pull-right"></i>
<i class="{{node.icon}}"></i>
{{node.name}}
</a>
</li>

View File

@@ -19,19 +19,29 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
public class EntityController : UmbracoAuthorizedJsonController
{
public IUmbracoEntity GetById(int id)
public EntityDisplay GetById(int id)
{
return Services.EntityService.Get(id);
return map((UmbracoEntity)Services.EntityService.Get(id, UmbracoObjectTypes.Document));
}
public IEnumerable<IUmbracoEntity> GetByIds([FromUri]int[] ids)
public IEnumerable<EntityDisplay> GetByIds([FromUri]int[] ids)
{
if (ids == null) throw new ArgumentNullException("ids");
return ids.Select(id => Services.EntityService.Get(id)).Where(entity => entity != null).ToList();
return ids.Select(id => map(((UmbracoEntity)Services.EntityService.Get(id, UmbracoObjectTypes.Document)))).Where(entity => entity != null).ToList();
}
private EntityDisplay map(UmbracoEntity input)
{
EntityDisplay output = new EntityDisplay();
output.Name = input.Name;
output.Id = input.Id;
output.Key = input.Key;
output.Icon = input.ContentTypeIcon;
return output;
}
//public IEnumerable<UmbracoEntity> GetContentByIds(int[] ids)
//{
// var list = new List<UmbracoEntity>();

View File

@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "entity", Namespace = "")]
public class EntityDisplay
{
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "id")]
public int Id { get; set; }
[DataMember(Name = "key")]
public Guid Key { get; set; }
[DataMember(Name = "icon")]
public string Icon { get; set; }
}
}

View File

@@ -39,7 +39,7 @@ namespace Umbraco.Web.Models.Mapping
//if there is no property editor it means that it is a legacy data type
// we cannot support editing with that so we'll just render the readonly value view.
display.View = GlobalSettings.Path.EnsureEndsWith('/') +
"views/propertyeditors/umbraco/readonlyvalue/readonlyvalue.html";
"views/propertyeditors/readonlyvalue/readonlyvalue.html";
}
else
{

View File

@@ -299,6 +299,7 @@
<Compile Include="Editors\AuthenticationController.cs" />
<Compile Include="Editors\ContentController.cs" />
<Compile Include="Editors\EntityController.cs" />
<Compile Include="Models\ContentEditing\EntityDisplay.cs" />
<Compile Include="Models\ContentEditing\TemplateBasic.cs" />
<Compile Include="Models\PagedResult.cs" />
<Compile Include="PropertyEditors\DatePropertyEditor.cs" />