If you haven't already seen Sir Trevor JS, then you must take a look now! It allows the user to insert blocks of different types, with a really nice interface.
There are many benefits to this approach in a responsive site, as the content types are separated using json and can be outputted in rows. I have used Sir Trevor JS along with Wagtail Streamfield, which does a similar thing.
But what if we want the same experience on an Angular project? well unfortunately the only version available is a wrapper around the main version, without proper Angular integration. I decided to write my own which could support the integration better. Here is how I did it.
First off we need to include angular.js in the page and add the ng-app to the html tag. Now we can create a controller for the editor with some default data:
Now we have some data we need assign the controller and add the loop which will output the blocks in the html page:
Note that we also included a directive attribute called 'block'. This is going to be a dynamic directive which changes the block type based on the data. Lets add the directive and a function to the controller to handle it:
In this updateType function we are finding the template based on the block type. But we are missing templates for the block types. Lets add those to the html:
Now the blocks are showing, we need to add the functionality to the controls to move blocks around, add and remove blocks. add these functions to your controller:
You can view the working version here:
http://kmturley.github.io/angular-sir-trevor/There are many benefits to this approach in a responsive site, as the content types are separated using json and can be outputted in rows. I have used Sir Trevor JS along with Wagtail Streamfield, which does a similar thing.
But what if we want the same experience on an Angular project? well unfortunately the only version available is a wrapper around the main version, without proper Angular integration. I decided to write my own which could support the integration better. Here is how I did it.
First off we need to include angular.js in the page and add the ng-app to the html tag. Now we can create a controller for the editor with some default data:
angular.module('app', []) .controller('editor', ['$scope', '$compile', '$templateCache', function ($scope, $compile, $templateCache) { 'use strict'; $scope.blocks = [ { type: 'text', content: '<h1>Angular Sir Trevor</h1><p>AngularJS block-based editor inspired by Sir Trevor JS</p>' }, { type: 'image', content: 'http://massimages.mobi/wp-content/uploads/forest-wallpaper-widescreen-hd-photograph-6.jpg' } ]; }])
Now we have some data we need assign the controller and add the loop which will output the blocks in the html page:
<div class="editor" ng-controller="editor"> <div block class="block {{ block.type }}" ng-repeat="block in blocks" ng-class="{ 'editing': block.edit }" ng-click="block.edit=true"></div> </div>
Note that we also included a directive attribute called 'block'. This is going to be a dynamic directive which changes the block type based on the data. Lets add the directive and a function to the controller to handle it:
// directive .directive('block', ['$window', '$compile', '$templateCache', function ($window, $compile, $templateCache) { 'use strict'; return { restrict: 'A', link: function (scope, element, attr, ctrl) { scope.updateType(element, scope); } }; }]) // add to the editor controller $scope.updateType = function (element, scope) { if (scope.block.type === 'text') { element.removeAttr('tabindex', '0'); element.html($templateCache.get(scope.block.type)); } else { element.attr('tabindex', '0'); element.html($templateCache.get(scope.block.type) + $templateCache.get('overlay')); } $compile(element.contents())(scope); };
In this updateType function we are finding the template based on the block type. But we are missing templates for the block types. Lets add those to the html:
<script type="text/ng-template" id="overlay"> <div class="overlay"> <div class="controls"> <button ng-click="moveUp(blocks, block)">▲</button> <button ng-click="remove(blocks, block)">X</button> <button ng-click="moveDown(blocks, block)">▼</button> </div> <p>UPLOAD FILE</p> <div class="area"><input upload type="file" /></div> <p>OR MODIFY EXISTING URL</p> <input paste type="text" ng-model="block.content" /> </div> </script> <script type="text/ng-template" id="text"> <div text contenteditable="true">{{ block.content }}</div> <div class="controls"> <button ng-click="moveUp(blocks, block)">▲</button> <button ng-click="remove(blocks, block)">X</button> <button ng-click="moveDown(blocks, block)">▼</button> </div> </script> <script type="text/ng-template" id="image"> <img image ng-src="{{ block.content }}" alt="" /> </script> <script type="text/ng-template" id="video"> <div class="wide"><iframe video content="{{ block.content }}" frameborder="0" allowfullscreen></iframe></div> </script>
Now the blocks are showing, we need to add the functionality to the controls to move blocks around, add and remove blocks. add these functions to your controller:
$scope.add = function (array, element) { array.push(element); }; $scope.remove = function (array, element) { var index = array.indexOf(element); if (index === -1) { return false; } array.splice(index, 1); }; $scope.moveUp = function (array, element) { var index = array.indexOf(element); if (index === -1) { return false; } if (array[index - 1]) { array.splice(index - 1, 2, array[index], array[index - 1]); } else { return 0; } }; $scope.moveDown = function (array, element) { var index = array.indexOf(element); if (index === -1) { return false; } if (array[index + 1]) { array.splice(index, 2, array[index + 1], array[index]); } else { return 0; } };
You can view the working version here:
And get the source code at:
https://github.com/kmturley/angular-sir-trevor
No comments:
Post a Comment