Compare commits
No commits in common. 'master' and '0.3.3' have entirely different histories.
@ -1,7 +0,0 @@
|
||||
language: node_js
|
||||
|
||||
node_js:
|
||||
- '0.10'
|
||||
|
||||
notifications:
|
||||
email: false
|
@ -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,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 +1,73 @@
|
||||
/**
|
||||
* @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()
|
||||
.directive('contenteditable', ['$timeout', function($timeout) { return {
|
||||
require: 'ngModel',
|
||||
link: function($scope, $element, attrs, ngModel) {
|
||||
var old_render
|
||||
// view -> model
|
||||
$element.bind('input', function(e) {
|
||||
$scope.$apply(function() {
|
||||
var html, html2, rerender
|
||||
html = $element.html()
|
||||
rerender = false
|
||||
if (attrs.stripBr && attrs.stripBr !== "false") {
|
||||
html = html.replace(/<br>$/, '')
|
||||
}
|
||||
if (attrs.noLineBreaks && attrs.noLineBreaks !== "false") {
|
||||
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.blur()
|
||||
$element.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)
|
||||
// model -> view
|
||||
old_render = ngModel.$render
|
||||
ngModel.$render = function() {
|
||||
var el, el2, range, sel
|
||||
if (!!old_render) {
|
||||
old_render()
|
||||
}
|
||||
$element.html(ngModel.$viewValue || '')
|
||||
el = $element.get(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 (attrs.selectNonEditable && attrs.selectNonEditable !== "false") {
|
||||
$element.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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}}]);
|
||||
}}])
|
||||
|
@ -0,0 +1,33 @@
|
||||
module.exports = (karma) ->
|
||||
karma.set
|
||||
basePath: '..'
|
||||
|
||||
frameworks: ['mocha']
|
||||
|
||||
files: [
|
||||
'bower_components/angular/angular.js'
|
||||
'angular-contenteditable.js'
|
||||
'test/unit/*.coffee'
|
||||
]
|
||||
|
||||
preprocessors: '**/*.coffee': 'coffee'
|
||||
|
||||
exclude: []
|
||||
|
||||
reporters: ['progress']
|
||||
|
||||
port: 9876
|
||||
|
||||
runnerPort: 9100
|
||||
|
||||
colors: true
|
||||
|
||||
logLevel: karma.LOG_INFO
|
||||
|
||||
autoWatch: true
|
||||
|
||||
browsers: ['Chrome']
|
||||
|
||||
captureTimeout: 60000
|
||||
|
||||
singleRun: false
|
@ -0,0 +1,3 @@
|
||||
describe 'radians', ->
|
||||
describe 'contenteditable', ->
|
||||
it 'passes', ->
|
@ -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