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:
Shannon
2014-05-06 18:06:41 +10:00
parent a846ba64eb
commit af732955fb
4 changed files with 146 additions and 120 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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;
});

View File

@@ -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>