Fixes up a bit more with tags look ahead, fixes up rte to show a loading... text so the UI is handled much better
This commit is contained in:
@@ -2,7 +2,9 @@ angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.RTEController",
|
||||
function ($rootScope, $scope, $q, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService, angularHelper, stylesheetResource) {
|
||||
|
||||
tinyMceService.configuration().then(function(tinyMceConfig){
|
||||
$scope.isLoading = true;
|
||||
|
||||
tinyMceService.configuration().then(function (tinyMceConfig) {
|
||||
|
||||
//config value from general tinymce.config file
|
||||
var validElements = tinyMceConfig.validElements;
|
||||
@@ -12,14 +14,14 @@ angular.module("umbraco")
|
||||
var extendedValidElements = "@[id|class|style],-div[id|dir|class|align|style],ins[datetime|cite],-ul[class|style],-li[class|style]";
|
||||
|
||||
var invalidElements = tinyMceConfig.inValidElements;
|
||||
var plugins = _.map(tinyMceConfig.plugins, function(plugin){
|
||||
if(plugin.useOnFrontend){
|
||||
return plugin.name;
|
||||
}
|
||||
}).join(" ");
|
||||
|
||||
var plugins = _.map(tinyMceConfig.plugins, function (plugin) {
|
||||
if (plugin.useOnFrontend) {
|
||||
return plugin.name;
|
||||
}
|
||||
}).join(" ");
|
||||
|
||||
var editorConfig = $scope.model.config.editor;
|
||||
if(!editorConfig || angular.isString(editorConfig)){
|
||||
if (!editorConfig || angular.isString(editorConfig)) {
|
||||
editorConfig = tinyMceService.defaultPrevalues();
|
||||
}
|
||||
|
||||
@@ -35,11 +37,11 @@ angular.module("umbraco")
|
||||
}
|
||||
|
||||
//queue rules loading
|
||||
angular.forEach(editorConfig.stylesheets, function(val, key){
|
||||
angular.forEach(editorConfig.stylesheets, function (val, key) {
|
||||
stylesheets.push("../css/" + val + ".css?" + new Date().getTime());
|
||||
|
||||
await.push(stylesheetResource.getRulesByName(val).then(function(rules) {
|
||||
angular.forEach(rules, function(rule) {
|
||||
|
||||
await.push(stylesheetResource.getRulesByName(val).then(function (rules) {
|
||||
angular.forEach(rules, function (rule) {
|
||||
var r = {};
|
||||
r.title = rule.name;
|
||||
if (rule.selector[0] == ".") {
|
||||
@@ -65,40 +67,39 @@ angular.module("umbraco")
|
||||
|
||||
//wait for queue to end
|
||||
$q.all(await).then(function () {
|
||||
|
||||
|
||||
//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,
|
||||
height: editorConfig.dimensions.height,
|
||||
width: editorConfig.dimensions.width,
|
||||
toolbar: toolbar,
|
||||
content_css: stylesheets.join(','),
|
||||
relative_urls: false,
|
||||
style_formats: styleFormats
|
||||
};
|
||||
//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,
|
||||
height: editorConfig.dimensions.height,
|
||||
width: editorConfig.dimensions.width,
|
||||
toolbar: toolbar,
|
||||
content_css: stylesheets.join(','),
|
||||
relative_urls: false,
|
||||
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 = $scope.model.alias + "_rte";
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
if (tinyMceConfig.customConfig) {
|
||||
angular.extend(baseLineConfigObj, tinyMceConfig.customConfig);
|
||||
}
|
||||
|
||||
//set all the things that user configs should not be able to override
|
||||
baseLineConfigObj.elements = $scope.model.alias + "_rte";
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
|
||||
//enable browser based spell checking
|
||||
editor.on('init', function(e) {
|
||||
editor.on('init', function (e) {
|
||||
editor.getBody().setAttribute('spellcheck', true);
|
||||
});
|
||||
|
||||
@@ -126,7 +127,7 @@ angular.module("umbraco")
|
||||
$scope.model.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//when buttons modify content
|
||||
editor.on('ExecCommand', function (e) {
|
||||
editor.save();
|
||||
@@ -137,26 +138,26 @@ angular.module("umbraco")
|
||||
|
||||
// Update model on keypress
|
||||
editor.on('KeyUp', function (e) {
|
||||
editor.save();
|
||||
angularHelper.safeApply($scope, function () {
|
||||
$scope.model.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.model.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.model.value = editor.getContent();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
editor.on('ObjectResized', function(e) {
|
||||
editor.on('ObjectResized', function (e) {
|
||||
var qs = "?width=" + e.width + "px&height=" + e.height + "px";
|
||||
var srcAttr = $(e.target).attr("src");
|
||||
var srcAttr = $(e.target).attr("src");
|
||||
var path = srcAttr.split("?")[0];
|
||||
$(e.target).attr("data-mce-src", path + qs);
|
||||
});
|
||||
@@ -176,19 +177,22 @@ angular.module("umbraco")
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** 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);
|
||||
|
||||
$scope.isLoading = false;
|
||||
|
||||
}, 200, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -203,7 +207,7 @@ angular.module("umbraco")
|
||||
// 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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-editor umb-rte">
|
||||
<textarea ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
|
||||
<div ng-if="isLoading">Loading...</div>
|
||||
<textarea ng-style="{ visibility : isLoading ? 'hidden' : 'visible'}" ng-model="model.value" rows="10" id="{{model.alias}}_rte"></textarea>
|
||||
</div>
|
||||
@@ -1,57 +1,63 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.TagsController",
|
||||
function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout) {
|
||||
function ($rootScope, $scope, $log, assetsService, umbRequestHelper, angularHelper, $timeout, $element) {
|
||||
|
||||
//load current value
|
||||
$scope.currentTags = [];
|
||||
if ($scope.model.value) {
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
}
|
||||
|
||||
//Helper method to add a tag on enter or on typeahead select
|
||||
function addTag(tagToAdd) {
|
||||
if (tagToAdd.length > 0) {
|
||||
if ($scope.currentTags.indexOf(tagToAdd) < 0) {
|
||||
$scope.currentTags.push(tagToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addTag = function (e) {
|
||||
var code = e.keyCode || e.which;
|
||||
if (code == 13) { //Enter keycode
|
||||
|
||||
if ($('#tags-Tags').parent().find(".tt-dropdown-menu .tt-cursor").length === 0) {
|
||||
//this is required, otherwise the html form will attempt to submit.
|
||||
e.preventDefault();
|
||||
addTag($scope.tagToAdd);
|
||||
$scope.tagToAdd = "";
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeTag = function (tag) {
|
||||
var i = $scope.currentTags.indexOf(tag);
|
||||
if (i >= 0) {
|
||||
$scope.currentTags.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
//sync model on submit (needed since we convert an array to string)
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = $scope.currentTags.join();
|
||||
});
|
||||
|
||||
//vice versa
|
||||
$scope.model.onValueChanged = function (newVal, oldVal) {
|
||||
//update the display val again if it has changed from the server
|
||||
$scope.model.val = newVal;
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
};
|
||||
$scope.isLoading = true;
|
||||
$scope.tagToAdd = "";
|
||||
|
||||
assetsService.loadJs("lib/typeahead/typeahead.bundle.min.js").then(function () {
|
||||
|
||||
$scope.isLoading = false;
|
||||
|
||||
//load current value
|
||||
$scope.currentTags = [];
|
||||
if ($scope.model.value) {
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
}
|
||||
|
||||
//Helper method to add a tag on enter or on typeahead select
|
||||
function addTag(tagToAdd) {
|
||||
if (tagToAdd.length > 0) {
|
||||
if ($scope.currentTags.indexOf(tagToAdd) < 0) {
|
||||
$scope.currentTags.push(tagToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.addTag = function (e) {
|
||||
var code = e.keyCode || e.which;
|
||||
if (code == 13) { //Enter keycode
|
||||
|
||||
//ensure that we're not pressing the enter key whilst selecting a typeahead value from the drop down
|
||||
if ($element.find('.tags-' + $scope.model.alias).parent().find(".tt-dropdown-menu .tt-cursor").length === 0) {
|
||||
//this is required, otherwise the html form will attempt to submit.
|
||||
e.preventDefault();
|
||||
//we need to use jquery because typeahead duplicates the text box
|
||||
addTag($scope.tagToAdd);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
$scope.removeTag = function (tag) {
|
||||
var i = $scope.currentTags.indexOf(tag);
|
||||
if (i >= 0) {
|
||||
$scope.currentTags.splice(i, 1);
|
||||
}
|
||||
};
|
||||
|
||||
//sync model on submit (needed since we convert an array to string)
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = $scope.currentTags.join();
|
||||
});
|
||||
|
||||
//vice versa
|
||||
$scope.model.onValueChanged = function (newVal, oldVal) {
|
||||
//update the display val again if it has changed from the server
|
||||
$scope.model.val = newVal;
|
||||
$scope.currentTags = $scope.model.value.split(",");
|
||||
};
|
||||
|
||||
//configure the tags data source
|
||||
//TODO: We'd like to be able to filter the shown list items to not show the tags that are currently
|
||||
// selected but that is difficult, i've tried a number of things and also this link suggests we cannot do
|
||||
@@ -90,28 +96,35 @@ angular.module("umbraco")
|
||||
|
||||
//configure the type ahead
|
||||
$timeout(function() {
|
||||
$('#tags-' + $scope.model.alias).typeahead(
|
||||
//use the default options
|
||||
null, {
|
||||
$element.find('.tags-' + $scope.model.alias).typeahead(
|
||||
{
|
||||
//This causes some strangeness as it duplicates the textbox, best leave off for now.
|
||||
hint: false,
|
||||
highlight: true,
|
||||
minLength: 1
|
||||
}, {
|
||||
//see: https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md#options
|
||||
// name = the data set name, we'll make this the tag group name
|
||||
name: $scope.model.config.group,
|
||||
displayKey: "value",
|
||||
source: tagsHound.ttAdapter(),
|
||||
highlight: true,
|
||||
hint: true
|
||||
}).bind("typeahead:selected", function (obj, datum, name) {
|
||||
|
||||
angularHelper.safeApply($scope, function () {
|
||||
addTag(datum["value"]);
|
||||
$scope.tagToAdd = "";
|
||||
});
|
||||
|
||||
}).bind("typeahead:autocompleted", function (obj, datum, name) {
|
||||
angularHelper.safeApply($scope, function () {
|
||||
addTag(datum["value"]);
|
||||
});
|
||||
|
||||
}).bind("typeahead:opened", function (obj) {
|
||||
console.log("opened ");
|
||||
});
|
||||
});
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
$('#tags-' + $scope.model.alias).typeahead('destroy');
|
||||
$element.find('.tags-' + $scope.model.alias).typeahead('destroy');
|
||||
delete tagsHound;
|
||||
});
|
||||
|
||||
|
||||
@@ -1,11 +1,19 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.TagsController" class="umb-editor umb-tags">
|
||||
|
||||
<div ng-if="isLoading">
|
||||
Loading...
|
||||
</div>
|
||||
|
||||
<span ng-repeat="tag in currentTags" ng-click="removeTag(tag)" class="label label-primary tag">{{tag}} <i class="icon icon-delete"></i></span>
|
||||
<ng-form>
|
||||
<div ng-if="!isLoading">
|
||||
<span ng-repeat="tag in currentTags" ng-click="removeTag(tag)" class="label label-primary tag">{{tag}} <i class="icon icon-delete"></i></span>
|
||||
|
||||
<input type="text"
|
||||
id="tags-{{model.alias}}"
|
||||
class="typeahead"
|
||||
ng-keydown="addTag($event)"
|
||||
placeholder="Type to add tags.."
|
||||
ng-model="tagToAdd" />
|
||||
<input type="text"
|
||||
class="typeahead tags-{{model.alias}}"
|
||||
ng-keydown="addTag($event)"
|
||||
placeholder="Type to add tags.."
|
||||
ng-model="tagToAdd" />
|
||||
</div>
|
||||
</ng-form>
|
||||
|
||||
</div>
|
||||
Reference in New Issue
Block a user