Skip to content

Instantly share code, notes, and snippets.

@hnq90
Created September 14, 2015 08:17
Show Gist options
  • Select an option

  • Save hnq90/3b4750122996894b7f52 to your computer and use it in GitHub Desktop.

Select an option

Save hnq90/3b4750122996894b7f52 to your computer and use it in GitHub Desktop.
Redactor Utils
utils: function()
{
return {
isMobile: function()
{
return /(iPhone|iPod|BlackBerry|Android)/.test(navigator.userAgent);
},
isDesktop: function()
{
return !/(iPhone|iPod|iPad|BlackBerry|Android)/.test(navigator.userAgent);
},
isString: function(obj)
{
return Object.prototype.toString.call(obj) == '[object String]';
},
isEmpty: function(html, removeEmptyTags)
{
html = html.replace(/[\u200B-\u200D\uFEFF]/g, '');
html = html.replace(/ /gi, '');
html = html.replace(/<\/?br\s?\/?>/g, '');
html = html.replace(/\s/g, '');
html = html.replace(/^<p>[^\W\w\D\d]*?<\/p>$/i, '');
html = html.replace(/<iframe(.*?[^>])>$/i, 'iframe');
html = html.replace(/<source(.*?[^>])>$/i, 'source');
// remove empty tags
if (removeEmptyTags !== false)
{
html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, '');
html = html.replace(/<[^\/>][^>]*><\/[^>]+>/gi, '');
}
html = $.trim(html);
return html === '';
},
normalize: function(str)
{
if (typeof(str) === 'undefined') return 0;
return parseInt(str.replace('px',''), 10);
},
hexToRgb: function(hex)
{
if (typeof hex == 'undefined') return;
if (hex.search(/^#/) == -1) return hex;
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b)
{
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return 'rgb(' + parseInt(result[1], 16) + ', ' + parseInt(result[2], 16) + ', ' + parseInt(result[3], 16) + ')';
},
getOuterHtml: function(el)
{
return $('<div>').append($(el).eq(0).clone()).html();
},
getAlignmentElement: function(el)
{
if ($.inArray(el.tagName, this.opts.alignmentTags) !== -1)
{
return $(el);
}
else
{
return $(el).closest(this.opts.alignmentTags.toString().toLowerCase(), this.$editor[0]);
}
},
removeEmptyAttr: function(el, attr)
{
var $el = $(el);
if (typeof $el.attr(attr) == 'undefined')
{
return true;
}
if ($el.attr(attr) === '')
{
$el.removeAttr(attr);
return true;
}
return false;
},
removeEmpty: function(i, s)
{
var $s = $($.parseHTML(s));
$s.find('.redactor-invisible-space').removeAttr('style').removeAttr('class');
if ($s.find('hr, br, img, iframe, source').length !== 0) return;
var text = $.trim($s.text());
if (this.utils.isEmpty(text, false))
{
$s.remove();
}
},
// save and restore scroll
saveScroll: function()
{
this.saveEditorScroll = this.$editor.scrollTop();
this.saveBodyScroll = $(window).scrollTop();
if (this.opts.scrollTarget) this.saveTargetScroll = $(this.opts.scrollTarget).scrollTop();
},
restoreScroll: function()
{
if (typeof this.saveScroll === 'undefined' && typeof this.saveBodyScroll === 'undefined') return;
$(window).scrollTop(this.saveBodyScroll);
this.$editor.scrollTop(this.saveEditorScroll);
if (this.opts.scrollTarget) $(this.opts.scrollTarget).scrollTop(this.saveTargetScroll);
},
// get invisible space element
createSpaceElement: function()
{
var space = document.createElement('span');
space.className = 'redactor-invisible-space';
space.innerHTML = this.opts.invisibleSpace;
return space;
},
// replace
removeInlineTags: function(node)
{
var tags = this.opts.inlineTags;
tags.push('span');
if (node.tagName == 'PRE') tags.push('a');
$(node).find(tags.join(',')).not('span.redactor-selection-marker').contents().unwrap();
},
replaceWithContents: function(node, removeInlineTags)
{
var self = this;
$(node).replaceWith(function()
{
if (removeInlineTags === true) self.utils.removeInlineTags(this);
return $(this).contents();
});
return $(node);
},
replaceToTag: function(node, tag, removeInlineTags)
{
var replacement;
var self = this;
$(node).replaceWith(function()
{
replacement = $('<' + tag + ' />').append($(this).contents());
for (var i = 0; i < this.attributes.length; i++)
{
replacement.attr(this.attributes[i].name, this.attributes[i].value);
}
if (removeInlineTags === true) self.utils.removeInlineTags(replacement);
return replacement;
});
return replacement;
},
// start and end of element
isStartOfElement: function()
{
var block = this.selection.getBlock();
if (!block) return false;
var offset = this.caret.getOffsetOfElement(block);
return (offset === 0) ? true : false;
},
isEndOfElement: function(element)
{
if (typeof element == 'undefined')
{
var element = this.selection.getBlock();
if (!element) return false;
}
var offset = this.caret.getOffsetOfElement(element);
var text = $.trim($(element).text()).replace(/\n\r\n/g, '');
return (offset == text.length) ? true : false;
},
isStartOfEditor: function()
{
var offset = this.caret.getOffsetOfElement(this.$editor[0]);
return (offset === 0) ? true : false;
},
isEndOfEditor: function()
{
var block = this.$editor[0];
var offset = this.caret.getOffsetOfElement(block);
var text = $.trim($(block).html().replace(/(<([^>]+)>)/gi,''));
return (offset == text.length) ? true : false;
},
// test blocks
isBlock: function(block)
{
block = block[0] || block;
return block && this.utils.isBlockTag(block.tagName);
},
isBlockTag: function(tag)
{
if (typeof tag == 'undefined') return false;
return this.reIsBlock.test(tag);
},
// tag detection
isTag: function(current, tag)
{
var element = $(current).closest(tag, this.$editor[0]);
if (element.length == 1)
{
return element[0];
}
return false;
},
// select all
isSelectAll: function()
{
return this.selectAll;
},
enableSelectAll: function()
{
this.selectAll = true;
},
disableSelectAll: function()
{
this.selectAll = false;
},
// parents detection
isRedactorParent: function(el)
{
if (!el)
{
return false;
}
if ($(el).parents('.redactor-editor').length === 0 || $(el).hasClass('redactor-editor'))
{
return false;
}
return el;
},
isCurrentOrParentHeader: function()
{
return this.utils.isCurrentOrParent(['H1', 'H2', 'H3', 'H4', 'H5', 'H6']);
},
isCurrentOrParent: function(tagName)
{
var parent = this.selection.getParent();
var current = this.selection.getCurrent();
if ($.isArray(tagName))
{
var matched = 0;
$.each(tagName, $.proxy(function(i, s)
{
if (this.utils.isCurrentOrParentOne(current, parent, s))
{
matched++;
}
}, this));
return (matched === 0) ? false : true;
}
else
{
return this.utils.isCurrentOrParentOne(current, parent, tagName);
}
},
isCurrentOrParentOne: function(current, parent, tagName)
{
tagName = tagName.toUpperCase();
return parent && parent.tagName === tagName ? parent : current && current.tagName === tagName ? current : false;
},
// browsers detection
isOldIe: function()
{
return (this.utils.browser('msie') && parseInt(this.utils.browser('version'), 10) < 9) ? true : false;
},
isLessIe10: function()
{
return (this.utils.browser('msie') && parseInt(this.utils.browser('version'), 10) < 10) ? true : false;
},
isIe11: function()
{
return !!navigator.userAgent.match(/Trident\/7\./);
},
browser: function(browser)
{
var ua = navigator.userAgent.toLowerCase();
var match = /(opr)[\/]([\w.]+)/.exec( ua ) ||
/(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
if (browser == 'safari') return (typeof match[3] != 'undefined') ? match[3] == 'safari' : false;
if (browser == 'version') return match[2];
if (browser == 'webkit') return (match[1] == 'chrome' || match[1] == 'opr' || match[1] == 'webkit');
if (match[1] == 'rv') return browser == 'msie';
if (match[1] == 'opr') return browser == 'webkit';
return browser == match[1];
},
strpos: function(haystack, needle, offset)
{
var i = haystack.indexOf(needle, offset);
return i >= 0 ? i : false;
},
disableBodyScroll: function()
{
var $body = $('html');
var windowWidth = window.innerWidth;
if (!windowWidth)
{
var documentElementRect = document.documentElement.getBoundingClientRect();
windowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
}
var isOverflowing = document.body.clientWidth < windowWidth;
var scrollbarWidth = this.utils.measureScrollbar();
$body.css('overflow', 'hidden');
if (isOverflowing) $body.css('padding-right', scrollbarWidth);
},
measureScrollbar: function()
{
var $body = $('body');
var scrollDiv = document.createElement('div');
scrollDiv.className = 'redactor-scrollbar-measure';
$body.append(scrollDiv);
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
$body[0].removeChild(scrollDiv);
return scrollbarWidth;
},
enableBodyScroll: function()
{
$('html').css({ 'overflow': '', 'padding-right': '' });
$('body').remove('redactor-scrollbar-measure');
}
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment