Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

/* http://github.com/mindmup/bootstrap-wysiwyg */
/*global jQuery, $, FileReader*/
/*jslint browser:true*/
(function ($) {
        'use strict';
        var readFileIntoDataUrl = function (fileInfo) {
                var loader = $.Deferred(),
                        fReader = new FileReader();
                fReader.onload = function (e) {
                        loader.resolve(e.target.result);
                };
                fReader.onerror = loader.reject;
                fReader.onprogress = loader.notify;
                fReader.readAsDataURL(fileInfo);
                return loader.promise();
        };
        $.fn.cleanHtml = function () {
                var html = $(this).html();
                return html && html.replace(/(<br>|\s|<div><br><\/div>|&nbsp;)*$/, '');
        };
        $.fn.wysiwyg = function (userOptions) {
                var editor = this,
                        selectedRange,
                        options,
                        toolbarBtnSelector,
                        updateToolbar = function () {
                                if (options.activeToolbarClass) {
                                        $(options.toolbarSelector).find(toolbarBtnSelector).each(function () {
                                                var command = $(this).data(options.commandRole);
                                                if (document.queryCommandState(command)) {
                                                        $(this).addClass(options.activeToolbarClass);
                                                } else {
                                                        $(this).removeClass(options.activeToolbarClass);
                                                }
                                        });
                                }
                        },
                        execCommand = function (commandWithArgs, valueArg) {
                                var commandArr = commandWithArgs.split(' '),
                                        command = commandArr.shift(),
                                        args = commandArr.join(' ') + (valueArg || '');
                                document.execCommand(command, 0, args);
                                updateToolbar();
                        },
                        bindHotkeys = function (hotKeys) {
                                $.each(hotKeys, function (hotkey, command) {
                                        editor.keydown(hotkey, function (e) {
                                                if (editor.attr('contenteditable') && editor.is(':visible')) {
                                                        e.preventDefault();
                                                        e.stopPropagation();
                                                        execCommand(command);
                                                }
                                        }).keyup(hotkey, function (e) {
                                                if (editor.attr('contenteditable') && editor.is(':visible')) {
                                                        e.preventDefault();
                                                        e.stopPropagation();
                                                }
                                        });
                                });
                        },
                        getCurrentRange = function () {
                                var sel = window.getSelection();
                                if (sel.getRangeAt && sel.rangeCount) {
                                        return sel.getRangeAt(0);
                                }
                        },
                        saveSelection = function () {
                                selectedRange = getCurrentRange();
                        },
                        restoreSelection = function () {
                                var selection = window.getSelection();
                                if (selectedRange) {
                                        try {
                                                selection.removeAllRanges();
                                        } catch (ex) {
                                                document.body.createTextRange().select();
                                                document.selection.empty();
                                        }

                                        selection.addRange(selectedRange);
                                }
                        },
                        insertFiles = function (files) {
                                editor.focus();
                                $.each(files, function (idx, fileInfo) {
                                        if (/^image\//.test(fileInfo.type)) {
                                                $.when(readFileIntoDataUrl(fileInfo)).done(function (dataUrl) {
                                                        execCommand('insertimage', dataUrl);
                                                }).fail(function (e) {
                                                        options.fileUploadError("file-reader", e);
                                                });
                                        } else {
                                                options.fileUploadError("unsupported-file-type", fileInfo.type);
                                        }
                                });
                        },
                        markSelection = function (input, color) {
                                restoreSelection();
                                if (document.queryCommandSupported('hiliteColor')) {
                                        document.execCommand('hiliteColor', 0, color || 'transparent');
                                }
                                saveSelection();
                                input.data(options.selectionMarker, color);
                        },
                        bindToolbar = function (toolbar, options) {
                                toolbar.find(toolbarBtnSelector).click(function () {
                                        restoreSelection();
                                        editor.focus();
                                        execCommand($(this).data(options.commandRole));
                                        saveSelection();
                                });
                                toolbar.find('[data-toggle=dropdown]').click(restoreSelection);

                                toolbar.find('input[type=text][data-' + options.commandRole + ']').on('webkitspeechchange change', function () {
                                        var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */
                                        this.value = '';
                                        restoreSelection();
                                        if (newValue) {
                                                editor.focus();
                                                execCommand($(this).data(options.commandRole), newValue);
                                        }
                                        saveSelection();
                                }).on('focus', function () {
                                        var input = $(this);
                                        if (!input.data(options.selectionMarker)) {
                                                markSelection(input, options.selectionColor);
                                                input.focus();
                                        }
                                }).on('blur', function () {
                                        var input = $(this);
                                        if (input.data(options.selectionMarker)) {
                                                markSelection(input, false);
                                        }
                                });
                                toolbar.find('input[type=file][data-' + options.commandRole + ']').change(function () {
                                        restoreSelection();
                                        if (this.type === 'file' && this.files && this.files.length > 0) {
                                                insertFiles(this.files);
                                        }
                                        saveSelection();
                                        this.value = '';
                                });
                        },
                        initFileDrops = function () {
                                editor.on('dragenter dragover', false)
                                        .on('drop', function (e) {
                                                var dataTransfer = e.originalEvent.dataTransfer;
                                                e.stopPropagation();
                                                e.preventDefault();
                                                if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
                                                        insertFiles(dataTransfer.files);
                                                }
                                        });
                        };
                options = $.extend({}, $.fn.wysiwyg.defaults, userOptions);
                toolbarBtnSelector = 'a[data-' + options.commandRole + '],button[data-' + options.commandRole + '],input[type=button][data-' + options.commandRole + ']';
                bindHotkeys(options.hotKeys);
                if (options.dragAndDropImages) {
                        initFileDrops();
                }
                bindToolbar($(options.toolbarSelector), options);
                editor.attr('contenteditable', true)
                        .on('mouseup keyup mouseout', function () {
                                saveSelection();
                                updateToolbar();
                        });
                $(window).bind('touchend', function (e) {
                        var isInside = (editor.is(e.target) || editor.has(e.target).length > 0),
                                currentRange = getCurrentRange(),
                                clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);
                        if (!clear || isInside) {
                                saveSelection();
                                updateToolbar();
                        }
                });
                return this;
        };
        $.fn.wysiwyg.defaults = {
                hotKeys: {
                        'ctrl+b meta+b': 'bold',
                        'ctrl+i meta+i': 'italic',
                        'ctrl+u meta+u': 'underline',
                        'ctrl+z meta+z': 'undo',
                        'ctrl+y meta+y meta+shift+z': 'redo',
                        'ctrl+l meta+l': 'justifyleft',
                        'ctrl+r meta+r': 'justifyright',
                        'ctrl+e meta+e': 'justifycenter',
                        'ctrl+j meta+j': 'justifyfull',
                        'shift+tab': 'outdent',
                        'tab': 'indent'
                },
                toolbarSelector: '[data-role=editor-toolbar]',
                commandRole: 'edit',
                activeToolbarClass: 'btn-info',
                selectionMarker: 'edit-focus-marker',
                selectionColor: 'darkgrey',
                dragAndDropImages: true,
                fileUploadError: function (reason, detail) { console.log("File upload error", reason, detail); }
        };
}(window.jQuery));