textangular
Version:
A radically powerful Text-Editor/Wysiwyg editor for Angular.js
176 lines (158 loc) • 6.03 kB
JavaScript
// NOTE: textAngularVersion must match the Gruntfile.js 'setVersion' task.... and have format v/d+./d+./d+
var textAngularVersion = 'v1.5.8'; // This is automatically updated during the build process to the current release!
// IE version detection - http://stackoverflow.com/questions/4169160/javascript-ie-detection-why-not-use-simple-conditional-comments
// We need this as IE sometimes plays funny tricks with the contenteditable.
// ----------------------------------------------------------
// If you're not in IE (or IE version is less than 5) then:
// ie === undefined
// If you're in IE (>=5) then you can determine which version:
// ie === 7; // IE7
// Thus, to detect IE:
// if (ie) {}
// And to detect the version:
// ie === 6 // IE6
// ie > 7 // IE8, IE9, IE10 ...
// ie < 9 // Anything less than IE9
// ----------------------------------------------------------
/* istanbul ignore next: untestable browser check */
var _browserDetect = {
ie: (function(){
var undef,
v = 3,
div = document.createElement('div'),
all = div.getElementsByTagName('i');
while (
div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->',
all[0]
);
return v > 4 ? v : undef;
}()),
webkit: /AppleWebKit\/([\d.]+)/i.test(navigator.userAgent),
isFirefox: navigator.userAgent.toLowerCase().indexOf('firefox') > -1
};
// Global to textAngular to measure performance where needed
var performance = performance || {};
performance.now = (function() {
return performance.now ||
performance.mozNow ||
performance.msNow ||
performance.oNow ||
performance.webkitNow ||
function() { return new Date().getTime(); };
})();
// usage is:
// var t0 = performance.now();
// doSomething();
// var t1 = performance.now();
// console.log('Took', (t1 - t0).toFixed(4), 'milliseconds to do something!');
//
// turn html into pure text that shows visiblity
function stripHtmlToText(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
var res = tmp.textContent || tmp.innerText || '';
res.replace('\u200B', ''); // zero width space
res = res.trim();
return res;
}
// get html
function getDomFromHtml(html)
{
var tmp = document.createElement("DIV");
tmp.innerHTML = html;
return tmp;
}
// Global to textAngular REGEXP vars for block and list elements.
var BLOCKELEMENTS = /^(address|article|aside|audio|blockquote|canvas|center|dd|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|noscript|ol|output|p|pre|section|table|tfoot|ul|video)$/i;
var LISTELEMENTS = /^(ul|li|ol)$/i;
var VALIDELEMENTS = /^(address|article|aside|audio|blockquote|canvas|center|dd|div|dl|fieldset|figcaption|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|noscript|ol|output|p|pre|section|table|tfoot|ul|video|li)$/i;
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Compatibility
/* istanbul ignore next: trim shim for older browsers */
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
/*
Custom stylesheet for the placeholders rules.
Credit to: http://davidwalsh.name/add-rules-stylesheets
*/
var sheet, addCSSRule, removeCSSRule, _addCSSRule, _removeCSSRule, _getRuleIndex;
/* istanbul ignore else: IE <8 test*/
if(_browserDetect.ie > 8 || _browserDetect.ie === undefined){
var _sheets = document.styleSheets;
/* istanbul ignore next: preference for stylesheet loaded externally */
for(var i = 0; i < _sheets.length; i++){
if(_sheets[i].media.length === 0 || _sheets[i].media.mediaText.match(/(all|screen)/ig)){
if(_sheets[i].href){
if(_sheets[i].href.match(/textangular\.(min\.|)css/ig)){
sheet = _sheets[i];
break;
}
}
}
}
/* istanbul ignore next: preference for stylesheet loaded externally */
if(!sheet){
// this sheet is used for the placeholders later on.
sheet = (function() {
// Create the <style> tag
var style = document.createElement("style");
/* istanbul ignore else : WebKit hack :( */
if(_browserDetect.webkit) style.appendChild(document.createTextNode(""));
// Add the <style> element to the page, add as first so the styles can be overridden by custom stylesheets
document.getElementsByTagName('head')[0].appendChild(style);
return style.sheet;
})();
}
// use as: addCSSRule("header", "float: left");
addCSSRule = function(selector, rules) {
return _addCSSRule(sheet, selector, rules);
};
_addCSSRule = function(_sheet, selector, rules){
var insertIndex;
var insertedRule;
// This order is important as IE 11 has both cssRules and rules but they have different lengths - cssRules is correct, rules gives an error in IE 11
/* istanbul ignore next: browser catches */
if(_sheet.cssRules) insertIndex = Math.max(_sheet.cssRules.length - 1, 0);
else if(_sheet.rules) insertIndex = Math.max(_sheet.rules.length - 1, 0);
/* istanbul ignore else: untestable IE option */
if(_sheet.insertRule) {
_sheet.insertRule(selector + "{" + rules + "}", insertIndex);
}
else {
_sheet.addRule(selector, rules, insertIndex);
}
/* istanbul ignore next: browser catches */
if(sheet.rules) insertedRule = sheet.rules[insertIndex];
else if(sheet.cssRules) insertedRule = sheet.cssRules[insertIndex];
// return the inserted stylesheet rule
return insertedRule;
};
_getRuleIndex = function(rule, rules) {
var i, ruleIndex;
for (i=0; i < rules.length; i++) {
/* istanbul ignore else: check for correct rule */
if (rules[i].cssText === rule.cssText) {
ruleIndex = i;
break;
}
}
return ruleIndex;
};
removeCSSRule = function(rule){
_removeCSSRule(sheet, rule);
};
/* istanbul ignore next: tests are browser specific */
_removeCSSRule = function(sheet, rule){
var rules = sheet.cssRules || sheet.rules;
if(!rules || rules.length === 0) return;
var ruleIndex = _getRuleIndex(rule, rules);
if(sheet.removeRule){
sheet.removeRule(ruleIndex);
}else{
sheet.deleteRule(ruleIndex);
}
};
}