Angular: Empty Fiddle
http://angularjs.org/
HTML
<script src="http://code.angularjs.org/angular-1.0.1.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.4.0/ui-bootstrap.js"></script>
<div ng-controller="MyCtrl">
<h1 editable model="name"></h1>
<h4 editable model="name"></h4>
<p editable model="name"></p>
<blockquote editable model="name"></blockquote>
made by <a href="https://twitter.com/edjafarov">@edjafarov</a>
</div>
CSS
/*!
* Bootstrap v2.3.2
*
* Copyright 2012 Twitter, Inc
* Licensed under the Apache License v2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Designed and built with all the love in the world @twitter by @mdo and @fat.
*/
.clearfix {
*zoom: 1;
}
.clearfix:before,
.clearfix:after {
display: table;
line-height: 0;
content: "";
}
.clearfix:after {
clear: both;
}
.hide-text {
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.input-block-level {
display: block;
width: 100%;
min-height: 30px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
nav,
section {
display: block;
}
audio,
canvas,
video {
display: inline-block;
*display: inline;
*zoom: 1;
}
audio:not([controls]) {
display: none;
}
html {
font-size: 100%;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
a:focus {
outline: thin dotted #333;
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
a:hover,
a:active {
outline: 0;
}
sub,
sup {
position: relative;
font-size: 75%;
line-height: 0;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
img {
width: auto\9;
height: auto;
max-width: 100%;
vertical-align: middle;
border: 0;
-ms-interpolation-mode: bicubic;
}
#map_canvas img,
.google-maps img {
max-width: none;
}
button,
input,
select,
textarea {
margin: 0;
font-size: 100%;
vertical-align: middle;
}
button,
input {
*overflow: visible;
line-height: normal;
}
button::-moz-focus-inner,
input::-moz-focus-inner {
padding: 0;
border: 0;
}
button,
html input[type="button"],
input[type="reset"],
input[type="submit"] {
cursor: pointer;
-webkit-appearance:...
JavaScript
var myApp = angular.module('myApp',['editable']);
function MyCtrl($scope) {
$scope.name = 'cl me, edit me, blur me';
}
var editableDirective = angular.module('editable', ['ui.bootstrap.position']);
editableDirective.directive('editable', ['$compile','$position', function($compile, $position){
return {
restrict: 'A',
scope: {
'model':'='
},
template: "<span ng-click='edit()' ng-bind-html-unsafe='model|newlines'></span><textarea ng-model='model' ng-show='editing' ng-style='style' ng-blur='done()'></textarea>",
link: function(scope, element){
scope.editing = false;
scope.multiline = false;
var fixedStyle;
scope.edit = function(){
fixedStyle = getFixedStyle(element.find('span'));
scope.editing = true;
scope.multiline = isMultiline();
var pos = $position.position(element.find('span'));
var style = {
width: pos.width + "px",
height: pos.height + "px",
position: 'absolute',
left: pos.left + "px",
'top': pos.top + "px"
}
angular.extend(style, fixedStyle)
scope.style = style;
setTimeout(function(){
element.find('textarea')[0].focus();
},20);
}
function isMultiline(){
var lineHeight = getStyle(element.find('span')[0], 'line-height');
var spanHeight = getStyle(element.find('span')[0], 'height');
return parseInt(spanHeight,10) >= 2*parseInt(lineHeight,10);
}
function getFixedStyle(el){
return {
margin: getStyle(el[0], 'margin'),
padding: getStyle(el[0], 'padding'),
font: getStyle(el[0], 'font'),
}
}
function getDimStyles(el){
var width = el.prop('offsetWidth');
var height = el.prop('offsetHeight');
return {
width: width + 'px',
height: height + 'px'
}
}
scope.$watch('model',function(){
...