Compare commits
No commits in common. 'master' and 'gh-pages' have entirely different histories.
@ -1,21 +0,0 @@
|
|||||||
# EditorConfig helps developers define and maintain consistent
|
|
||||||
# coding styles between different editors and IDEs
|
|
||||||
# editorconfig.org
|
|
||||||
|
|
||||||
root = true
|
|
||||||
|
|
||||||
|
|
||||||
[*]
|
|
||||||
|
|
||||||
# Change these settings to your own preference
|
|
||||||
indent_style = space
|
|
||||||
indent_size = 2
|
|
||||||
|
|
||||||
# We recommend you to keep these unchanged
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
insert_final_newline = true
|
|
||||||
|
|
||||||
[*.md]
|
|
||||||
trim_trailing_whitespace = false
|
|
@ -1 +0,0 @@
|
|||||||
* text=auto
|
|
@ -1,3 +1,6 @@
|
|||||||
node_modules
|
node_modules
|
||||||
bower_components
|
bower_components
|
||||||
|
dist
|
||||||
|
.tmp
|
||||||
|
.sass-cache
|
||||||
.idea
|
.idea
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
{
|
|
||||||
"node": true,
|
|
||||||
"browser": true,
|
|
||||||
"es5": true,
|
|
||||||
"esnext": true,
|
|
||||||
"bitwise": true,
|
|
||||||
"camelcase": true,
|
|
||||||
"curly": true,
|
|
||||||
"eqeqeq": true,
|
|
||||||
"immed": true,
|
|
||||||
"indent": 2,
|
|
||||||
"latedef": true,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg": true,
|
|
||||||
"quotmark": "single",
|
|
||||||
"regexp": true,
|
|
||||||
"undef": true,
|
|
||||||
"unused": true,
|
|
||||||
"strict": true,
|
|
||||||
"trailing": true,
|
|
||||||
"smarttabs": true,
|
|
||||||
"globals": {
|
|
||||||
"angular": false
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
|
|
||||||
node_js:
|
|
||||||
- '0.10'
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
@ -1,24 +0,0 @@
|
|||||||
# global module:false
|
|
||||||
|
|
||||||
module.exports = (grunt) ->
|
|
||||||
|
|
||||||
grunt.initConfig
|
|
||||||
pkg: grunt.file.readJSON 'package.json'
|
|
||||||
meta:
|
|
||||||
test: 'test'
|
|
||||||
karma:
|
|
||||||
e2e: configFile: 'karma.coffee'
|
|
||||||
e2e_ci:
|
|
||||||
configFile: 'karma.coffee'
|
|
||||||
singleRun: true
|
|
||||||
browsers: ['PhantomJS']
|
|
||||||
jshint:
|
|
||||||
src: ['angular-contenteditable.js']
|
|
||||||
options:
|
|
||||||
asi: true
|
|
||||||
|
|
||||||
require('matchdep').filterDev('grunt-*').forEach grunt.loadNpmTasks
|
|
||||||
|
|
||||||
grunt.registerTask 'test', ['karma:e2e_ci']
|
|
||||||
grunt.registerTask 'lint', ['jshint']
|
|
||||||
grunt.registerTask 'default', ['lint' , 'test']
|
|
@ -1,21 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 Dmitri Akatov
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
@ -1,53 +0,0 @@
|
|||||||
# angular-contenteditable
|
|
||||||
[![Build Status](https://img.shields.io/travis/akatov/angular-contenteditable.svg)](https://travis-ci.org/akatov/angular-contenteditable)
|
|
||||||
[![Dependency Status](https://img.shields.io/gemnasium/akatov/angular-contenteditable.svg)](https://gemnasium.com/akatov/angular-contenteditable)
|
|
||||||
[![endorse](https://api.coderwall.com/akatov/endorsecount.png)](https://coderwall.com/akatov)
|
|
||||||
|
|
||||||
An AngularJS directive to bind html tags with the `contenteditable` attribute to models.
|
|
||||||
|
|
||||||
## Install
|
|
||||||
|
|
||||||
```bash
|
|
||||||
bower install angular-contenteditable
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
angular.module('myapp', ['contenteditable'])
|
|
||||||
.controller('Ctrl', ['$scope', function($scope) {
|
|
||||||
$scope.model="<i>interesting</i> stuff"
|
|
||||||
}])
|
|
||||||
```
|
|
||||||
|
|
||||||
```html
|
|
||||||
<div ng-controller="Ctrl">
|
|
||||||
<span contenteditable="true"
|
|
||||||
ng-model="model"
|
|
||||||
strip-br="true"
|
|
||||||
select-non-editable="true">
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notice
|
|
||||||
|
|
||||||
The directive currently does not work in any version of Internet Explorer or Opera < 15.
|
|
||||||
Both browsers don't fire the `input` event for contenteditable fields.
|
|
||||||
|
|
||||||
In Chrome, when a contenteditable element X contains a non-contenteditable
|
|
||||||
element Y as the last element, then the behaviour of the caret is the following:
|
|
||||||
|
|
||||||
* When X has style `display` set to `block` or `inline-block`, then the caret
|
|
||||||
moves to the very far right edge of X when it is _immediately_ at the end of X
|
|
||||||
(inserting spaces moves the caret back).
|
|
||||||
|
|
||||||
* When X has style `display` set to `inline`, then the caret disappears instead.
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm install
|
|
||||||
bower install
|
|
||||||
grunt
|
|
||||||
```
|
|
@ -1,165 +0,0 @@
|
|||||||
|
|
||||||
/**
|
|
||||||
* we copied most of the 'element' scenario dsl so we can keep the old actions
|
|
||||||
* and also add the 'enter' and modified 'html' actions.
|
|
||||||
* @see https://github.com/angular/angular.js/blob/master/src/ngScenario/dsl.js
|
|
||||||
* @see http://stackoverflow.com/questions/12575199/how-to-test-a-contenteditable-field-based-on-a-td-using-angularjs-e2e-testing
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
* element(selector, label).count() get the number of elements that match selector
|
|
||||||
* element(selector, label).click() clicks an element
|
|
||||||
* element(selector, label).mouseover() mouseover an element
|
|
||||||
* element(selector, label).mousedown() mousedown an element
|
|
||||||
* element(selector, label).mouseup() mouseup an element
|
|
||||||
* element(selector, label).query(fn) executes fn(selectedElements, done)
|
|
||||||
* element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
|
|
||||||
* element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
|
|
||||||
* element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
|
|
||||||
* element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
|
|
||||||
* element(selector, label).enter(value) sets the text if the element is contenteditable
|
|
||||||
*/
|
|
||||||
angular.scenario.dsl('element', function() {
|
|
||||||
var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
|
|
||||||
var VALUE_METHODS = [
|
|
||||||
'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
|
|
||||||
'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
|
|
||||||
];
|
|
||||||
var chain = {};
|
|
||||||
|
|
||||||
chain.count = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' count", function($window, $document, done) {
|
|
||||||
try {
|
|
||||||
done(null, $document.elements().length);
|
|
||||||
} catch (e) {
|
|
||||||
done(null, 0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.click = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' click", function($window, $document, done) {
|
|
||||||
var elements = $document.elements();
|
|
||||||
var href = elements.attr('href');
|
|
||||||
var eventProcessDefault = elements.trigger('click')[0];
|
|
||||||
|
|
||||||
if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
|
|
||||||
this.application.navigateTo(href, function() {
|
|
||||||
done();
|
|
||||||
}, done);
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.dblclick = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' dblclick", function($window, $document, done) {
|
|
||||||
var elements = $document.elements();
|
|
||||||
var href = elements.attr('href');
|
|
||||||
var eventProcessDefault = elements.trigger('dblclick')[0];
|
|
||||||
|
|
||||||
if (href && elements[0].nodeName.toUpperCase() === 'A' && eventProcessDefault) {
|
|
||||||
this.application.navigateTo(href, function() {
|
|
||||||
done();
|
|
||||||
}, done);
|
|
||||||
} else {
|
|
||||||
done();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.mouseover = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' mouseover", function($window, $document, done) {
|
|
||||||
var elements = $document.elements();
|
|
||||||
elements.trigger('mouseover');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.mousedown = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' mousedown", function($window, $document, done) {
|
|
||||||
var elements = $document.elements();
|
|
||||||
elements.trigger('mousedown');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.mouseup = function() {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' mouseup", function($window, $document, done) {
|
|
||||||
var elements = $document.elements();
|
|
||||||
elements.trigger('mouseup');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
chain.query = function(fn) {
|
|
||||||
return this.addFutureAction('element ' + this.label + ' custom query', function($window, $document, done) {
|
|
||||||
fn.call(this, $document.elements(), done);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
angular.forEach(KEY_VALUE_METHODS, function(methodName) {
|
|
||||||
chain[methodName] = function(name, value) {
|
|
||||||
var args = arguments,
|
|
||||||
futureName = (args.length == 1)
|
|
||||||
? "element '" + this.label + "' get " + methodName + " '" + name + "'"
|
|
||||||
: "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" + value + "'";
|
|
||||||
|
|
||||||
return this.addFutureAction(futureName, function($window, $document, done) {
|
|
||||||
var element = $document.elements();
|
|
||||||
done(null, element[methodName].apply(element, args));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
angular.forEach(VALUE_METHODS, function(methodName) {
|
|
||||||
chain[methodName] = function(value) {
|
|
||||||
var args = arguments,
|
|
||||||
futureName = (args.length == 0)
|
|
||||||
? "element '" + this.label + "' " + methodName
|
|
||||||
: futureName = "element '" + this.label + "' set " + methodName + " to '" + value + "'";
|
|
||||||
|
|
||||||
return this.addFutureAction(futureName, function($window, $document, done) {
|
|
||||||
var element = $document.elements();
|
|
||||||
done(null, element[methodName].apply(element, args));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// =============== These are the methods ================ \\
|
|
||||||
chain.enter = function(value) {
|
|
||||||
return this.addFutureAction("element '" + this.label + "' enter '" + value + "'", function($window, $document, done) {
|
|
||||||
var element = $document.elements()
|
|
||||||
if (element.is('[contenteditable=""]')
|
|
||||||
|| (element.attr('contenteditable')
|
|
||||||
&& element.attr('contenteditable').match(/true/i))) {
|
|
||||||
element.text(value)
|
|
||||||
element.trigger('input')
|
|
||||||
}
|
|
||||||
done()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
chain.html = function(value) {
|
|
||||||
var args = arguments,
|
|
||||||
futureName = (args.length == 0)
|
|
||||||
? "element '" + this.label + "' html"
|
|
||||||
: futureName = "element '" + this.label + "' set html to '" + value + "'";
|
|
||||||
return this.addFutureAction(futureName, function($window, $document, done) {
|
|
||||||
var element = $document.elements();
|
|
||||||
element.html.apply(element, args)
|
|
||||||
if (args.length > 0
|
|
||||||
&& (element.is('[contenteditable=""]')
|
|
||||||
|| (element.attr('contenteditable')
|
|
||||||
&& element.attr('contenteditable').match(/true/i)))) {
|
|
||||||
element.trigger('input')
|
|
||||||
}
|
|
||||||
done(null, element.html.apply(element, args));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
return function(selector, label) {
|
|
||||||
this.dsl.using(selector, label);
|
|
||||||
return chain;
|
|
||||||
};
|
|
||||||
});
|
|
@ -1,98 +0,0 @@
|
|||||||
/**
|
|
||||||
* @see http://docs.angularjs.org/guide/concepts
|
|
||||||
* @see http://docs.angularjs.org/api/ng.directive:ngModel.NgModelController
|
|
||||||
* @see https://github.com/angular/angular.js/issues/528#issuecomment-7573166
|
|
||||||
*/
|
|
||||||
|
|
||||||
angular.module('contenteditable', [])
|
|
||||||
.directive('contenteditable', ['$timeout', function($timeout) { return {
|
|
||||||
restrict: 'A',
|
|
||||||
require: '?ngModel',
|
|
||||||
link: function(scope, element, attrs, ngModel) {
|
|
||||||
// don't do anything unless this is actually bound to a model
|
|
||||||
if (!ngModel) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// options
|
|
||||||
var opts = {}
|
|
||||||
angular.forEach([
|
|
||||||
'stripBr',
|
|
||||||
'noLineBreaks',
|
|
||||||
'selectNonEditable',
|
|
||||||
'moveCaretToEndOnChange',
|
|
||||||
], function(opt) {
|
|
||||||
var o = attrs[opt]
|
|
||||||
opts[opt] = o && o !== 'false'
|
|
||||||
})
|
|
||||||
|
|
||||||
// view -> model
|
|
||||||
element.bind('input', function(e) {
|
|
||||||
scope.$apply(function() {
|
|
||||||
var html, html2, rerender
|
|
||||||
html = element.text()
|
|
||||||
rerender = false
|
|
||||||
if (opts.stripBr) {
|
|
||||||
html = html.replace(/<br>$/, '')
|
|
||||||
}
|
|
||||||
if (opts.noLineBreaks) {
|
|
||||||
html2 = html.replace(/<div>/g, '').replace(/<br>/g, '').replace(/<\/div>/g, '')
|
|
||||||
if (html2 !== html) {
|
|
||||||
rerender = true
|
|
||||||
html = html2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ngModel.$setViewValue(html)
|
|
||||||
if (rerender) {
|
|
||||||
ngModel.$render()
|
|
||||||
}
|
|
||||||
if (html === '') {
|
|
||||||
// the cursor disappears if the contents is empty
|
|
||||||
// so we need to refocus
|
|
||||||
$timeout(function(){
|
|
||||||
element[0].blur()
|
|
||||||
element[0].focus()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// model -> view
|
|
||||||
var oldRender = ngModel.$render
|
|
||||||
ngModel.$render = function() {
|
|
||||||
var el, el2, range, sel
|
|
||||||
if (!!oldRender) {
|
|
||||||
oldRender()
|
|
||||||
}
|
|
||||||
element.html(ngModel.$viewValue || '')
|
|
||||||
if (opts.moveCaretToEndOnChange) {
|
|
||||||
el = element[0]
|
|
||||||
range = document.createRange()
|
|
||||||
sel = window.getSelection()
|
|
||||||
if (el.childNodes.length > 0) {
|
|
||||||
el2 = el.childNodes[el.childNodes.length - 1]
|
|
||||||
range.setStartAfter(el2)
|
|
||||||
} else {
|
|
||||||
range.setStartAfter(el)
|
|
||||||
}
|
|
||||||
range.collapse(true)
|
|
||||||
sel.removeAllRanges()
|
|
||||||
sel.addRange(range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (opts.selectNonEditable) {
|
|
||||||
element.bind('click', function(e) {
|
|
||||||
var range, sel, target
|
|
||||||
target = e.toElement
|
|
||||||
if (target !== this && angular.element(target).attr('contenteditable') === 'false') {
|
|
||||||
range = document.createRange()
|
|
||||||
sel = window.getSelection()
|
|
||||||
range.setStartBefore(target)
|
|
||||||
range.setEndAfter(target)
|
|
||||||
sel.removeAllRanges()
|
|
||||||
sel.addRange(range)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}]);
|
|
@ -1,24 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "angular-contenteditable",
|
|
||||||
"version": "0.3.7",
|
|
||||||
"main": "angular-contenteditable.js",
|
|
||||||
"ignore": [
|
|
||||||
".*",
|
|
||||||
"README.md",
|
|
||||||
"Gruntfile.coffee",
|
|
||||||
"package.json",
|
|
||||||
"components",
|
|
||||||
"node_modules",
|
|
||||||
"src",
|
|
||||||
"test"
|
|
||||||
],
|
|
||||||
"devDependencies": {
|
|
||||||
"angular": "*",
|
|
||||||
"angular-mocks": "~1.0.5",
|
|
||||||
"angular-scenario": "~1.0.5",
|
|
||||||
"expect": "~0.2.0",
|
|
||||||
"jquery": "~2.0.2",
|
|
||||||
"bootstrap-css": "~2.3.2",
|
|
||||||
"angular-bootstrap": "~0.4.0"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 260 B After Width: | Height: | Size: 260 B |
Before Width: | Height: | Size: 361 B After Width: | Height: | Size: 361 B |
Before Width: | Height: | Size: 367 B After Width: | Height: | Size: 367 B |
@ -0,0 +1,18 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>angular-contenteditable</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>angular contenteditable</h1>
|
||||||
|
<h2>examples<h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href='examples/no-line-breaks.html'>no-line-breaks.html</a></li>
|
||||||
|
<li><a href='examples/select-non-editable.html'>select-non-editable.html</a></li>
|
||||||
|
<li><a href='examples/simple.html'>simple.html</a></li>
|
||||||
|
<li><a href='examples/strip-br.html'>strip-br.html</a></li>
|
||||||
|
<li><a href='examples/typeahead1.html'>typeahead1.html</a></li>
|
||||||
|
<li><a href='examples/typeahead2.html'>typeahead2.html</a></li>
|
||||||
|
<li><a href='examples/typeahead3.html'>typeahead3.html</a></li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,41 +0,0 @@
|
|||||||
module.exports = (karma) ->
|
|
||||||
toServe = for file in [
|
|
||||||
'bower_components/**/*.css'
|
|
||||||
'bower_components/*/*.js'
|
|
||||||
'test/fixtures/**/*'
|
|
||||||
]
|
|
||||||
pattern: file
|
|
||||||
watched: false
|
|
||||||
included: false
|
|
||||||
served: true
|
|
||||||
|
|
||||||
karma.set
|
|
||||||
frameworks: ['ng-scenario']
|
|
||||||
|
|
||||||
preprocessors: '**/*.coffee': 'coffee'
|
|
||||||
|
|
||||||
files: [
|
|
||||||
'test/e2e/**/*.coffee'
|
|
||||||
'angular-contenteditable.js'
|
|
||||||
'angular-contenteditable-scenario.js'
|
|
||||||
].concat toServe
|
|
||||||
|
|
||||||
exclude: []
|
|
||||||
|
|
||||||
reporters: ['progress']
|
|
||||||
|
|
||||||
port: 9876
|
|
||||||
|
|
||||||
runnerPort: 9100
|
|
||||||
|
|
||||||
colors: true
|
|
||||||
|
|
||||||
logLevel: karma.LOG_INFO
|
|
||||||
|
|
||||||
autoWatch: true
|
|
||||||
|
|
||||||
browsers: ['Chrome']
|
|
||||||
|
|
||||||
captureTimeout: 60000
|
|
||||||
|
|
||||||
singleRun: false
|
|
@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "angular-contenteditable",
|
|
||||||
"version": "0.3.7",
|
|
||||||
"description": "angular model for the 'contenteditable' html attribute",
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/akatov/angular-contenteditable.git"
|
|
||||||
},
|
|
||||||
"main": "angular-contenteditable.js",
|
|
||||||
"directories": {
|
|
||||||
"test": "test"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"install": "bower install",
|
|
||||||
"test": "grunt test"
|
|
||||||
},
|
|
||||||
"repository": "",
|
|
||||||
"keywords": [
|
|
||||||
"angular",
|
|
||||||
"extension"
|
|
||||||
],
|
|
||||||
"author": "Dmitri Akatov",
|
|
||||||
"license": "BSD",
|
|
||||||
"devDependencies": {
|
|
||||||
"matchdep": "~0.3.0",
|
|
||||||
"grunt": "~0.4.1",
|
|
||||||
"grunt-cli": "~0.1.13",
|
|
||||||
"grunt-contrib-jshint": "~0.7.1",
|
|
||||||
"grunt-karma": "~0.6.2",
|
|
||||||
"bower": "~1.3.5",
|
|
||||||
"karma": "~0.10.2",
|
|
||||||
"karma-ng-scenario": "0.1.0",
|
|
||||||
"karma-coffee-preprocessor": "0.1.0"
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
describe 'module contenteditable', ->
|
|
||||||
describe 'directive contenteditable', ->
|
|
||||||
describe 'simple application', ->
|
|
||||||
beforeEach ->
|
|
||||||
browser().navigateTo 'base/test/fixtures/simple.html'
|
|
||||||
|
|
||||||
it 'should update the model from the view (simple text)', ->
|
|
||||||
element('#input').enter('abc')
|
|
||||||
expect(element('#input').html()).toBe 'abc'
|
|
||||||
expect(element('#output').html()).toBe 'abc'
|
|
||||||
|
|
||||||
it 'should update the model from the view (text with spans)', ->
|
|
||||||
element('#input').html('abc <span style="color:red">red</span>')
|
|
||||||
expect(element('#input span').html()).toBe 'red'
|
|
||||||
expect(element('#output').html()).toBe 'abc <span style="color:red">red</span>'
|
|
||||||
|
|
||||||
it 'should update the view from the model', ->
|
|
||||||
input('model').enter('oops')
|
|
||||||
expect(element('#input').html()).toBe 'oops'
|
|
||||||
expect(element('#output').html()).toBe 'oops'
|
|
||||||
input('model').enter('a <span style="color:red">red</span> b')
|
|
||||||
expect(element('#input').html()).toBe 'a <span style="color:red">red</span> b'
|
|
||||||
expect(element('#input span').html()).toBe 'red'
|
|
||||||
expect(element('#output').html()).toBe 'a <span style="color:red">red</span> b'
|
|
@ -1,97 +0,0 @@
|
|||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require 'tmpdir'
|
|
||||||
require 'json'
|
|
||||||
|
|
||||||
puts 'running post-commit hook'
|
|
||||||
|
|
||||||
BOWER = JSON.parse File.read 'bower.json'
|
|
||||||
|
|
||||||
def commit
|
|
||||||
@commit ||= `git log | head -1 | cut -d' ' -f2`
|
|
||||||
end
|
|
||||||
|
|
||||||
# get version of library from bower.json
|
|
||||||
def bower_version(library)
|
|
||||||
BOWER["dependencies"][library] || BOWER["devDependencies"][library]
|
|
||||||
end
|
|
||||||
|
|
||||||
# return the base url for a library from bower / github
|
|
||||||
def library_base_url(library)
|
|
||||||
# TODO: figure out how to clean the cache so we can use `bower --offline`
|
|
||||||
(@library_base_url ||= {})[library] ||=
|
|
||||||
JSON.parse(`bower lookup #{library} --json`)["url"]
|
|
||||||
.sub(/^git:\/\/github.com/, 'https://rawgithub.com')
|
|
||||||
.sub(/\.git$/, "/#{bower_version(library).sub(/~/, '')}/")
|
|
||||||
end
|
|
||||||
|
|
||||||
# transform script ref to bower URL
|
|
||||||
def script_url(src)
|
|
||||||
if src =~ /\/bower_components\//
|
|
||||||
parts = src.split('/bower_components/')[1].split('/')
|
|
||||||
library_base_url(parts[0]) + parts.drop(1).join('/')
|
|
||||||
else
|
|
||||||
src.sub(/^\.\.\/\.\./,
|
|
||||||
'https://rawgithub.com/akatov/angular-contenteditable/master')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# link href
|
|
||||||
# script src
|
|
||||||
def replace_script_and_link(contents)
|
|
||||||
["script src", "link href"].reduce(contents) do |c, tag|
|
|
||||||
c.gsub /#{tag}="([^"]*)"/ do
|
|
||||||
"#{tag}=\"#{script_url($1)}\""
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def index_header
|
|
||||||
<<EOF
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<title>angular-contenteditable</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>angular contenteditable</h1>
|
|
||||||
<h2>examples<h2>
|
|
||||||
<ul>
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
|
|
||||||
def index_footer
|
|
||||||
<<EOF
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
EOF
|
|
||||||
end
|
|
||||||
|
|
||||||
puts commit
|
|
||||||
|
|
||||||
def execute
|
|
||||||
Dir.mktmpdir do |temp|
|
|
||||||
FileUtils.cp_r 'test/fixtures/', temp
|
|
||||||
FileUtils.mv "#{temp}/fixtures", "#{temp}/examples"
|
|
||||||
File.open("#{temp}/index.html", File::CREAT | File::WRONLY) do |index_file|
|
|
||||||
index_file.write index_header
|
|
||||||
Dir.glob("#{temp}/examples/*.html").each do |file_name|
|
|
||||||
bn = File.basename file_name
|
|
||||||
puts "changing references in #{bn}"
|
|
||||||
File.write file_name, replace_script_and_link(File.read file_name)
|
|
||||||
index_file.write " <li><a href='examples/#{bn}'>#{bn}</a></li>\n"
|
|
||||||
end
|
|
||||||
index_file.write index_footer
|
|
||||||
end
|
|
||||||
`git checkout gh-pages`
|
|
||||||
`git rm -r examples`
|
|
||||||
['index.html', 'examples'].each do |f|
|
|
||||||
FileUtils.cp_r "#{temp}/#{f}", '.'
|
|
||||||
`git add #{f}`
|
|
||||||
end
|
|
||||||
`git commit --message "updating gh-pages for commit #{commit}"`
|
|
||||||
`git checkout master`
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
execute
|
|
Reference in New Issue