<commit_before>(function () {
    "use strict";

    angular.module("blocktrail.wallet")
        .controller("WalletCtrl", WalletCtrl);

    function WalletCtrl($scope, $state, $rootScope, storageService, walletsManagerService, activeWallet,
                        CONFIG, settingsService, setupService, $timeout, launchService, blocktrailLocalisation,
                        dialogService, $translate, Currencies, AppVersionService, $filter, Contacts,
                        trackingService, $interval) {

        $scope.settings = settingsService.getReadOnlySettings();
        $scope.walletData = activeWallet.getReadOnlyWalletData();
        $scope.sideNavList = [
            {
                stateHref: $state.href("app.wallet.summary"),
                activeStateName: "app.wallet.summary",
                linkText: "MY_WALLET",
                linkIcon: "bticon-doc-text",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.send"),
                activeStateName: "app.wallet.send",
                linkText: "SEND",
                linkIcon: "bticon-forward-outline",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.receive"),
                activeStateName: "app.wallet.receive",
                linkText: "RECEIVE",
                linkIcon: "bticon-reply-outline",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.buybtc.choose"),
                activeStateName: "app.wallet.buybtc",
                linkText: "BUYBTC_NAVTITLE",
                linkIcon: "bticon-credit-card",
                isHidden: !CONFIG.BUYBTC
            },
            {
                stateHref: $state.href("app.wallet.settings"),
                activeStateName: "app.wallet.settings",
                linkText: "SETTINGS",
                linkIcon: "bticon-cog",
                isHidden: false
            }
        ];
        $scope.appStoreButtonsData = {
            config: CONFIG,
            settings: $scope.settings
        };

        /**
         * Start temporal implementation for multiple wallets
         * TODO Add select to template
         */
        $scope.debugMode = CONFIG.DEBUG;
        $scope.activeWalletIdentifier = $scope.walletData.identifier;
        $scope.walletsList = walletsManagerService.getWalletsList();

        // track when wallet is activated (first time > 0 balance)
        if (!$scope.settings.walletActivated) {
            var walletActivatedInterval = $interval(function() {
                if ($scope.walletData.balance + $scope.walletData.uncBalance > 0) {
                    settingsService.updateSettingsUp({walletActivated: true});
                    trackingService.trackEvent(trackingService.EVENTS.ACTIVATED);

                    $interval.cancel(walletActivatedInterval);
                }
            }, 60000);
        }

        $scope.onChangeActiveWallet = function(id) {
            walletsManagerService.setActiveWalletById(id)
                .then(function() {
                    $scope.isInitWallet = false;
                    $state.reload();
                });
        };

        // add info from setup process to the settings
        setupService.getUserInfo().then(function(userInfo) {
            if (userInfo.username || userInfo.displayName || userInfo.email) {
                var updateSettings = {
                    username: userInfo.username || $scope.settings.username,
                    displayName: userInfo.displayName || $scope.settings.displayName,
                    email: userInfo.email || $scope.settings.email
                };

                setupService.clearUserInfo();
                settingsService.updateSettingsUp(updateSettings);
            }
        }, function(e) {
            console.error('getUserInfo', e);
        });

        $scope.$on('glidera_complete', function(event, transaction) {
            dialogService.alert({
                body: $translate.instant('MSG_BUYBTC_GLIDERA_COMPLETE_BODY', {
                    qty: transaction.qty
                }),
                title: 'MSG_BUYBTC_GLIDERA_COMPLETE'
            })
        });

        /**
         * Fetch extra languages
         *
         * Check for extra languages to enable, if one is preferred, prompt user to switch
         *
         * TODO move the logic to service
         */
        $rootScope.fetchExtraLanguages = launchService.getWalletConfig()
            .then(function(result) {
                settingsService.getSettings().then(function(settings) {
                    // check if we need to display any update notices
                    AppVersionService.checkVersion(settings.latestVersionWeb, result.versionInfo.web, AppVersionService.CHECKS.LOGGEDIN);

                    // store the latest version we've used
                    if (!settings.latestVersionWeb || semver.gt(CONFIG.VERSION, settings.latestVersionWeb)) {
                        $timeout(function() {
                            var updateSettings = {
                                latestVersionWeb: CONFIG.VERSION
                            };

                            settingsService.updateSettingsUp(updateSettings);
                        }, 500);
                    }
                });

                if (result.currencies) {
                    result.currencies.forEach(function (currency) {
                        Currencies.enableCurrency(currency);
                    });
                }

                return result.extraLanguages.concat(CONFIG.EXTRA_LANGUAGES).unique();
            })
            .then(function(extraLanguages) {
                return settingsService.getSettings().then(function(settings) {
                    (settings.extraLanguages || []).forEach(function(language) {
                        blocktrailLocalisation.enableLanguage(language);
                    });

                    // determine (new) preferred language
                    var r = blocktrailLocalisation.parseExtraLanguages(extraLanguages);

                    if (r) {
                        var newLanguages = r[0];
                        var preferredLanguage = r[1];

                        // store extra languages
                        var updateSettings = {
                            extraLanguages: settings.extraLanguages.concat(newLanguages).unique()
                        };

                        return settingsService.updateSettingsUp(updateSettings)
                            .then(function(settings) {
                                // check if we have a new preferred language
                                if (preferredLanguage != settings.language && extraLanguages.indexOf(preferredLanguage) !== -1) {
                                    // prompt to enable
                                    return dialogService.prompt({
                                        body: $translate.instant('MSG_BETTER_LANGUAGE', {
                                            oldLanguage: $translate.instant(blocktrailLocalisation.languageName(settings.language)),
                                            newLanguage: $translate.instant(blocktrailLocalisation.languageName(preferredLanguage))
                                        }),
                                        title: $translate.instant('MSG_BETTER_LANGUAGE_TITLE'),
                                        prompt: false
                                    })
                                        .result
                                        .then(function() {
                                            // enable new language
                                            var updateSettings = {
                                                extraLanguages: preferredLanguage
                                            };
                                            // TODO root scope language should have a subscription on property language from settings service
                                            $rootScope.changeLanguage(preferredLanguage);
                                            return settingsService.updateSettingsUp(updateSettings);
                                        });
                                }
                            });
                    }
                });
            })
            .then(
                function() {},
                function(e) {
                    console.error('extraLanguages', e && (e.msg || e.message || "" + e));
                }
            );

        $rootScope.getPrice = function() {
            return Currencies.updatePrices(false)
                .then(function(prices) {
                    $rootScope.bitcoinPrices = prices;
                });
        };

        $rootScope.syncContacts = function() {
            //sync any changes to contacts
            Contacts.list()
                .catch(function(err) {
                    $log.error(err);
                });
         };

        // do initial updates then poll for changes, all with small offsets to reducing blocking / slowing down of rendering
        $timeout(function() {
            $rootScope.syncContacts();
        }, 500);

        $timeout(function() {
            $rootScope.getPrice();
        }, 1000);

        // TODO settings polling move to a settingsService
        $timeout(function() {
            settingsService.syncSettingsDown();
        }, 302000); // 5 min + slight offset not to collide
    }
})();
<commit_msg>only show MSG_BETTER_LANGUAGE when possible<commit_after>(function () {
    "use strict";

    angular.module("blocktrail.wallet")
        .controller("WalletCtrl", WalletCtrl);

    function WalletCtrl($scope, $state, $rootScope, storageService, walletsManagerService, activeWallet,
                        CONFIG, settingsService, setupService, $timeout, launchService, blocktrailLocalisation,
                        dialogService, $translate, Currencies, AppVersionService, $filter, Contacts,
                        trackingService, $interval) {

        $scope.settings = settingsService.getReadOnlySettings();
        $scope.walletData = activeWallet.getReadOnlyWalletData();
        $scope.sideNavList = [
            {
                stateHref: $state.href("app.wallet.summary"),
                activeStateName: "app.wallet.summary",
                linkText: "MY_WALLET",
                linkIcon: "bticon-doc-text",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.send"),
                activeStateName: "app.wallet.send",
                linkText: "SEND",
                linkIcon: "bticon-forward-outline",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.receive"),
                activeStateName: "app.wallet.receive",
                linkText: "RECEIVE",
                linkIcon: "bticon-reply-outline",
                isHidden: false
            },
            {
                stateHref: $state.href("app.wallet.buybtc.choose"),
                activeStateName: "app.wallet.buybtc",
                linkText: "BUYBTC_NAVTITLE",
                linkIcon: "bticon-credit-card",
                isHidden: !CONFIG.BUYBTC
            },
            {
                stateHref: $state.href("app.wallet.settings"),
                activeStateName: "app.wallet.settings",
                linkText: "SETTINGS",
                linkIcon: "bticon-cog",
                isHidden: false
            }
        ];
        $scope.appStoreButtonsData = {
            config: CONFIG,
            settings: $scope.settings
        };

        /**
         * Start temporal implementation for multiple wallets
         * TODO Add select to template
         */
        $scope.debugMode = CONFIG.DEBUG;
        $scope.activeWalletIdentifier = $scope.walletData.identifier;
        $scope.walletsList = walletsManagerService.getWalletsList();

        // track when wallet is activated (first time > 0 balance)
        if (!$scope.settings.walletActivated) {
            var walletActivatedInterval = $interval(function() {
                if ($scope.walletData.balance + $scope.walletData.uncBalance > 0) {
                    settingsService.updateSettingsUp({walletActivated: true});
                    trackingService.trackEvent(trackingService.EVENTS.ACTIVATED);

                    $interval.cancel(walletActivatedInterval);
                }
            }, 60000);
        }

        $scope.onChangeActiveWallet = function(id) {
            walletsManagerService.setActiveWalletById(id)
                .then(function() {
                    $scope.isInitWallet = false;
                    $state.reload();
                });
        };

        // add info from setup process to the settings
        setupService.getUserInfo().then(function(userInfo) {
            if (userInfo.username || userInfo.displayName || userInfo.email) {
                var updateSettings = {
                    username: userInfo.username || $scope.settings.username,
                    displayName: userInfo.displayName || $scope.settings.displayName,
                    email: userInfo.email || $scope.settings.email
                };

                setupService.clearUserInfo();
                settingsService.updateSettingsUp(updateSettings);
            }
        }, function(e) {
            console.error('getUserInfo', e);
        });

        $scope.$on('glidera_complete', function(event, transaction) {
            dialogService.alert({
                body: $translate.instant('MSG_BUYBTC_GLIDERA_COMPLETE_BODY', {
                    qty: transaction.qty
                }),
                title: 'MSG_BUYBTC_GLIDERA_COMPLETE'
            })
        });

        /**
         * Fetch extra languages
         *
         * Check for extra languages to enable, if one is preferred, prompt user to switch
         *
         * TODO move the logic to service
         */
        $rootScope.fetchExtraLanguages = launchService.getWalletConfig()
            .then(function(result) {
                settingsService.getSettings().then(function(settings) {
                    // check if we need to display any update notices
                    AppVersionService.checkVersion(settings.latestVersionWeb, result.versionInfo.web, AppVersionService.CHECKS.LOGGEDIN);

                    // store the latest version we've used
                    if (!settings.latestVersionWeb || semver.gt(CONFIG.VERSION, settings.latestVersionWeb)) {
                        $timeout(function() {
                            var updateSettings = {
                                latestVersionWeb: CONFIG.VERSION
                            };

                            settingsService.updateSettingsUp(updateSettings);
                        }, 500);
                    }
                });

                if (result.currencies) {
                    result.currencies.forEach(function (currency) {
                        Currencies.enableCurrency(currency);
                    });
                }

                return result.extraLanguages.concat(CONFIG.EXTRA_LANGUAGES).unique();
            })
            .then(function(extraLanguages) {
                return settingsService.getSettings().then(function(settings) {
                    (settings.extraLanguages || []).forEach(function(language) {
                        blocktrailLocalisation.enableLanguage(language);
                    });

                    // determine (new) preferred language
                    var r = blocktrailLocalisation.parseExtraLanguages(extraLanguages);

                    if (r) {
                        var newLanguages = r[0];
                        var preferredLanguage = r[1];

                        // store extra languages
                        var updateSettings = {
                            extraLanguages: settings.extraLanguages.concat(newLanguages).unique()
                        };

                        return settingsService.updateSettingsUp(updateSettings)
                            .then(function(settings) {
                                // check if we have a new preferred language
                                if (preferredLanguage && settings.language && preferredLanguage !== settings.language && extraLanguages.indexOf(preferredLanguage) !== -1) {
                                    // prompt to enable
                                    return dialogService.prompt({
                                        body: $translate.instant('MSG_BETTER_LANGUAGE', {
                                            oldLanguage: $translate.instant(blocktrailLocalisation.languageName(settings.language)),
                                            newLanguage: $translate.instant(blocktrailLocalisation.languageName(preferredLanguage))
                                        }),
                                        title: $translate.instant('MSG_BETTER_LANGUAGE_TITLE'),
                                        prompt: false
                                    })
                                        .result
                                        .then(function() {
                                            // enable new language
                                            var updateSettings = {
                                                extraLanguages: preferredLanguage
                                            };
                                            // TODO root scope language should have a subscription on property language from settings service
                                            $rootScope.changeLanguage(preferredLanguage);
                                            return settingsService.updateSettingsUp(updateSettings);
                                        });
                                }
                            });
                    }
                });
            })
            .then(
                function() {},
                function(e) {
                    console.error('extraLanguages', e && (e.msg || e.message || "" + e));
                }
            );

        $rootScope.getPrice = function() {
            return Currencies.updatePrices(false)
                .then(function(prices) {
                    $rootScope.bitcoinPrices = prices;
                });
        };

        $rootScope.syncContacts = function() {
            //sync any changes to contacts
            Contacts.list()
                .catch(function(err) {
                    $log.error(err);
                });
         };

        // do initial updates then poll for changes, all with small offsets to reducing blocking / slowing down of rendering
        $timeout(function() {
            $rootScope.syncContacts();
        }, 500);

        $timeout(function() {
            $rootScope.getPrice();
        }, 1000);

        // TODO settings polling move to a settingsService
        $timeout(function() {
            settingsService.syncSettingsDown();
        }, 302000); // 5 min + slight offset not to collide
    }
})();
<|endoftext|>


<commit_before>(function($) {

    $.Redactor.prototype.iframely = function() {
        return {

            langs: {
                en: {
                    'iframely': 'Embed',
                    'enter-url': 'Enter URL you want to embed'
                }
            },

            getTemplate: function() {
				return String()
				+ '
'
					+ '
'
						+ '' + this.lang.get('enter-url') + ''
						+ '<input type="text" id="redactor-insert-iframely-area" />'
					+ '
'
                    + '
'
                        + ' '
                    + '
'
					+ '
'
						+ '<button id="redactor-modal-button-action">Insert</button>'
						+ '<button id="redactor-modal-button-cancel">Cancel</button>'
					+ '
'
				+ '
';
            },

            init: function() {

                this.iframely.cache = {};

                var button = this.button.addAfter('image', 'iframely', this.lang.get('iframely'));
                this.button.addCallback(button, this.iframely.show);

                this.core.element().on('linkify.callback.redactor', this.iframely.linkify);
            },

            linkify: function($elements) {

                var that = this;

                $elements.each(function(i, el) {

                    var $el = $(el);
                    if ($el.is('a')) {
                        var uri = $el.attr('href');

                        var otherParagraphElements = $el.parent().contents().filter(function() {
                            var text = $.trim(this.textContent);
                            if (text.length === 1 && text.charCodeAt(0) === 8203) {
                                // Clear ZERO WIDTH SPACE.
                                text = '';
                            }
                            if (text) {
                                var href = this.getAttribute && this.getAttribute('href');
                                if (href !== uri) {
                                    // Paragraph has another links.
                                    return true;
                                }
                                if (!href) {
                                    // Paragraph has another text.
                                    return true;
                                }
                            }
                        });

                        if (otherParagraphElements.length) {
                            // Prevent insert inside paragraph with text.
                            return;
                        }

                        that.iframely.fetchUrl(uri, function(error, html) {

                            // buffer
                            that.buffer.set();

                            // insert
                            that.air.collapsed();
                            $el.parent().html(html);
                        });
                    }
                });
            },

            show: function() {

                var that = this;

                this.modal.addTemplate('iframely', this.iframely.getTemplate());

                this.modal.load('iframely', this.lang.get('iframely'), 700);

                // action button
                this.modal.getActionButton().text(this.lang.get('insert')).on('click', this.iframely.insert);
                this.modal.show();

                // Move modal to top.
                setTimeout(function() {

                    var $modalParent = $(that.modal.getModal()).parent();
                    var previewHeight = $(window).height() - $modalParent.height() - 16;

                    $modalParent.css('margin-top', '16px');

                    $('#redactor-modal-iframely-preview').css('max-height', previewHeight + 'px');

                }, 1);

                var $input = $('#redactor-insert-iframely-area');

                var keyupTimeout = null;
                $input.keyup(function() {

                    if (keyupTimeout) {

                        // Wait for next preview.

                        clearTimeout(keyupTimeout);

                        keyupTimeout = setTimeout(function() {
                            that.iframely.preview();
                            keyupTimeout = null;
                        }, 1000);

                    } else {

                        // First preview start immediately.

                        keyupTimeout = setTimeout(function() {
                            keyupTimeout = null;
                        }, 1000);

                        that.iframely.preview();
                    }
                });

                // focus
                if (this.detect.isDesktop()) {
                    setTimeout(function() {
                        $input.focus();
                    }, 1);
                }
            },

            preview: function() {

                var $input = $('#redactor-insert-iframely-area');

                var uri = $.trim($input.val());
                var previousUri = $.trim($input.attr('data-previous-value'));

                if (uri === previousUri) {
                    return;
                }

                $input.removeAttr('data-preview-html');
                $input.attr('data-previous-value', uri);

                var $preview = $('#redactor-modal-iframely-preview');

                var loadingTimeout = setTimeout(function() {
                    $preview.text('Loading...');
                }, 1500);

                this.iframely.fetchUrl(uri, function(error, html) {

                    clearTimeout(loadingTimeout);

                    if (error || !html) {

                        $preview.html(' ');

                    } else {

                        // Store result for later use.
                        $input.attr('data-preview-html', html);

                        $preview.html(html);
                    }
                });
            },

            insert: function() {

                var that = this;
                var $input = $('#redactor-insert-iframely-area');
                var uri = $.trim($input.val());
                var previewHtml = $input.attr('data-preview-html');

                function insert(html) {
                    that.modal.close();
                    that.placeholder.hide();

                    // buffer
                    that.buffer.set();

                    // insert
                    that.air.collapsed();
                    that.insert.html(html);
                }

                if (previewHtml) {

                    insert(previewHtml);

                } else {

                    this.iframely.fetchUrl(uri, function(error, html) {

                        if (error || !html) {

                            var $preview = $('#redactor-modal-iframely-preview');
                            $preview.text('Sorry, no embeds for this URL');

                        } else {

                            insert(html);
                        }
                    });
                }
            },

            fetchUrl: function(uri, cb) {

                if (!uri.match(/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)\.(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i)) {
                    return cb();
                }

                var that = this;

                var data = that.iframely.cache[uri];

                if (data) {
                    return cb(data.error, data.html);
                }

                $.ajax({
                    url: this.opts.oembedEndpoint || 'http://open.iframe.ly/api/oembed',
                    dataType: "json",
                    data: {
                        url: uri,
                        origin: 'redactor'
                    },
                    success: function(data, textStatus, jqXHR) {

                        var html;

                        if (data && data.html) {
                            html = data.html;
                        } else if (data && !data.html && data.type === 'photo' && data.url) {
                            html = '';
                        }

                        that.iframely.cache[uri] = {
                            html: html
                        };

                        html = '
' + html + '
';

                        cb(null, html);
                    },
                    error: function(jqXHR, textStatus, errorThrown) {
                        console.error(jqXHR && jqXHR.responseText || textStatus);

                        // TODO: parse responseText.
                        var error = jqXHR && jqXHR.responseText || textStatus;

                        that.iframely.cache[uri] = {
                            error: error
                        };

                        cb(error);
                    }
                });
            }

        };
    };
})(jQuery);<commit_msg>Fix JavaScript-based embeds<commit_after>(function($) {

    $.Redactor.prototype.iframely = function() {
        return {

            langs: {
                en: {
                    'iframely': 'Embed',
                    'enter-url': 'Enter URL you want to embed'
                }
            },

            getTemplate: function() {
				return String()
				+ '
'
					+ '
'
						+ '' + this.lang.get('enter-url') + ''
						+ '<input type="text" id="redactor-insert-iframely-area" />'
					+ '
'
                    + '
'
                        + ' '
                    + '
'
					+ '
'
						+ '<button id="redactor-modal-button-action">Insert</button>'
						+ '<button id="redactor-modal-button-cancel">Cancel</button>'
					+ '
'
				+ '
';
            },

            init: function() {

                this.iframely.cache = {};

                var button = this.button.addAfter('image', 'iframely', this.lang.get('iframely'));
                this.button.addCallback(button, this.iframely.show);

                this.core.element().on('linkify.callback.redactor', this.iframely.linkify);
                this.core.element().on('syncBefore.callback.redactor', this.iframely.syncBefore);
            },

            syncBefore: function(html) {
                // Restore original embed code from embed wrapper attribute value.
                var $data = $('
').html(html);
                $data.find('[data-embed-code]').each(function() {
                    var $this = $(this);
                    $this.html($this.attr('data-embed-code'));
                });

                return $data.html();
            },

            linkify: function($elements) {

                var that = this;

                $elements.each(function(i, el) {

                    var $el = $(el);
                    if ($el.is('a')) {
                        var uri = $el.attr('href');

                        var otherParagraphElements = $el.parent().contents().filter(function() {
                            var text = $.trim(this.textContent);
                            if (text.length === 1 && text.charCodeAt(0) === 8203) {
                                // Clear ZERO WIDTH SPACE.
                                text = '';
                            }
                            if (text) {
                                var href = this.getAttribute && this.getAttribute('href');
                                if (href !== uri) {
                                    // Paragraph has another links.
                                    return true;
                                }
                                if (!href) {
                                    // Paragraph has another text.
                                    return true;
                                }
                            }
                        });

                        if (otherParagraphElements.length) {
                            // Prevent insert inside paragraph with text.
                            return;
                        }

                        that.iframely.fetchUrl(uri, function(error, html) {

                            // buffer
                            that.buffer.set();

                            // insert
                            that.air.collapsed();
                            $el.parent().html(html);
                        });
                    }
                });
            },

            show: function() {

                var that = this;

                this.modal.addTemplate('iframely', this.iframely.getTemplate());

                this.modal.load('iframely', this.lang.get('iframely'), 700);

                // action button
                this.modal.getActionButton().text(this.lang.get('insert')).on('click', this.iframely.insert);
                this.modal.show();

                // Move modal to top.
                setTimeout(function() {

                    var $modalParent = $(that.modal.getModal()).parent();
                    var previewHeight = $(window).height() - $modalParent.height() - 16;

                    $modalParent.css('margin-top', '16px');

                    $('#redactor-modal-iframely-preview').css('max-height', previewHeight + 'px');

                }, 1);

                var $input = $('#redactor-insert-iframely-area');

                var keyupTimeout = null;
                $input.keyup(function() {

                    if (keyupTimeout) {

                        // Wait for next preview.

                        clearTimeout(keyupTimeout);

                        keyupTimeout = setTimeout(function() {
                            that.iframely.preview();
                            keyupTimeout = null;
                        }, 1000);

                    } else {

                        // First preview start immediately.

                        keyupTimeout = setTimeout(function() {
                            keyupTimeout = null;
                        }, 1000);

                        that.iframely.preview();
                    }
                });

                // focus
                if (this.detect.isDesktop()) {
                    setTimeout(function() {
                        $input.focus();
                    }, 1);
                }
            },

            preview: function() {

                var $input = $('#redactor-insert-iframely-area');

                var uri = $.trim($input.val());
                var previousUri = $.trim($input.attr('data-previous-value'));

                if (uri === previousUri) {
                    return;
                }

                $input.removeAttr('data-preview-html');
                $input.attr('data-previous-value', uri);

                var $preview = $('#redactor-modal-iframely-preview');

                var loadingTimeout = setTimeout(function() {
                    $preview.text('Loading...');
                }, 1500);

                this.iframely.fetchUrl(uri, function(error, html) {

                    clearTimeout(loadingTimeout);

                    if (error || !html) {

                        $preview.html(' ');

                    } else {

                        // Store result for later use.
                        $input.attr('data-preview-html', html);

                        $preview.html(html);
                    }
                });
            },

            insert: function() {

                var that = this;
                var $input = $('#redactor-insert-iframely-area');
                var uri = $.trim($input.val());
                var previewHtml = $input.attr('data-preview-html');

                function insert(html) {
                    that.modal.close();
                    that.placeholder.hide();

                    // buffer
                    that.buffer.set();

                    // insert
                    that.air.collapsed();
                    that.insert.html(html);
                }

                if (previewHtml) {

                    insert(previewHtml);

                } else {

                    this.iframely.fetchUrl(uri, function(error, html) {

                        if (error || !html) {

                            var $preview = $('#redactor-modal-iframely-preview');
                            $preview.text('Sorry, no embeds for this URL');

                        } else {

                            insert(html);
                        }
                    });
                }
            },

            fetchUrl: function(uri, cb) {

                if (!uri.match(/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)\.(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/i)) {
                    return cb();
                }

                var that = this;

                var data = that.iframely.cache[uri];

                if (data) {
                    return cb(data.error, data.html);
                }

                $.ajax({
                    url: this.opts.oembedEndpoint || 'http://open.iframe.ly/api/oembed',
                    dataType: "json",
                    data: {
                        url: uri,
                        origin: 'redactor'
                    },
                    success: function(data, textStatus, jqXHR) {

                        var html;

                        if (data && data.html) {
                            html = data.html;
                        } else if (data && !data.html && data.type === 'photo' && data.url) {
                            html = '';
                        }

                        that.iframely.cache[uri] = {
                            html: html
                        };

                        var $div = $('
')
                            .attr('data-oembed-url', uri)
                            .html(html);

                        if (html && html.indexOf('</script>') > -1) {
                            // Store embed code with


<commit_before>/**
 * holds references to all available CodeMirror instances on the page
 * @type {Array}
 */
var editors = [];
var currentEditor = null;
var TranslatorsDeskGlobals = {}

var currentContextMenuTargetEditor = null;
var ContextMenuObjects = {};
ContextMenuObjects.translators_desk_ner_submenu =
	[
		{
			header: 'NER'
		},
		{
			text: ' Add NER markers',
			action: function(e){
				window.spm = e;
				var editor = currentContextMenuTargetEditor;
				mark_selection_as_ner(editor);
			}
		},
		{
			text: ' Clear NER markers',
			action: function(e){
				window.spm = e;
				var editor = currentContextMenuTargetEditor;
				unmark_selection_as_ner(editor);
			}
		}
	]
ContextMenuObjects .translators_desk_selected_text_menu = ContextMenuObjects.translators_desk_ner_submenu;

/**
 * Instantiates all available codemirror_blocks as CodeMirror instances
 */

$(".codemirror_block").each(function(){
	var editor = CodeMirror($(this)[0], {
	  value: "",
	  mode: "simple",
	  theme: 'eclipse',
	  lineNumbers: true,
	  lineWrapping: true,
	  styleSelectedText: true,
	  dragDrop: false,
	  extraKeys: {"Ctrl-Space": "translators_desk_aspell"}
	});

	/**
	 * Dynamically adds `get_selected_range` function to the editor instance
	 */
	editor.get_selected_range = function() {
	  return { from: editor.getCursor(true), to: editor.getCursor(false) };
	};
	editors.push(editor);
})

/**
 * Configures Per-language auto-suggestion query thresholds
 */

TranslatorsDeskGlobals.word_length_query_threshold = {}
TranslatorsDeskGlobals.word_length_query_threshold['en'] = 3
TranslatorsDeskGlobals.word_length_query_threshold['hi'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['pa'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['te'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['ta'] = 2

var editor_word_length_query_threshold;
/**
 * Instantiates Translators Desk Word Suggesstion
 */
CodeMirror.commands.translators_desk_aspell = function(editor) {
	editor_word_length_query_threshold = TranslatorsDeskGlobals.word_length_query_threshold[get_editor_language_menu(editor).val()]
	if(editor.currentWord && editor_word_length_query_threshold && editor.currentWord.trim().length > editor_word_length_query_threshold ){
		//Only consider words of length more than 3
		socket.emit("translanslators_desk_get_word_suggesstion",
					{
						data: editor.currentWord,
						lang: get_editor_language_menu(editors[0]).val()
					})

		var socket_response_listener = function(data){
			// TODO : The removelistener code is not working now
			// Fix this
			// Remove corresponding event listener
			socket.removeListener("translanslators_desk_get_word_suggesstion_"+$.md5(editor.currentWord.toLowerCase()), socket_response_listener )

			//Display the hint
			editor.showHint({
								hint: CodeMirror.hint.translators_desk_aspell,
								translators_desk_aspell_suggesstions: JSON.parse(data)
							});
		}
		socket.on("translanslators_desk_get_word_suggesstion_"+$.md5(editor.currentWord.toLowerCase()), socket_response_listener);
	}
}

/**
 * Gets the editor_id corresponding to a translators desk menu item
 * @param  menu_item jquery_selector_object
 * @return int
 */
function get_corresponding_editor_id_from_menu_item(menu_item){
	return $(menu_item).parents(".codemirror_menu").attr("td-editor-id");
}
/**
 * Gets the editor object corresponding to a translators desk menu item
 * @param  menu_item jquery_selector_object
 * @return CodeMirror editor object
 */
function get_corresponding_editor_from_menu_item(menu_item){
	var editor_id = parseInt(get_corresponding_editor_id_from_menu_item(menu_item));
	return editors[editor_id-1];
}

/**
 * Gets the editor_id corresponding to a translators desk codemirror element
 * @param  codemirror_element jquery_selector_object
 * @return int
 */
function get_corresponding_editor_id(codemirror_element){
	return $(codemirror_element).parents(".codemirror_block").attr("td-editor-id");
}
/**
 * Gets the editor object corresponding to a translators desk codemirror element
 * @param  codemirror_element jquery_selector_object
 * @return CodeMirror editor object
 */
function get_corresponding_editor(codemirror_element){
	var editor_id = parseInt(get_corresponding_editor_id(codemirror_element));
	return editors[editor_id-1];
}

function get_editor_id(editor){
	return $(editor.getWrapperElement()).parents(".codemirror_block").attr("td-editor-id");
}

/**
 * Marks a selected range as NER
 */
function mark_selection_as_ner(editor){
	if(editor.somethingSelected() && editor.getSelection().trim() != "" ){
		var selected_range = editor.get_selected_range();

		//Unmark all previous marks in that range
		unmark_selection_as_ner(editor);

		var selection = editor.markText(selected_range.from,
			selected_range.to,
			{
				className: "translators-desk-marker-ner",
				addToHistory: true,
			});
	}else{
			//TODO : Add handler for NER click on no selection
			console.log("You have not selected text yet");
	}
}
/**
 * Removes ner-marks from a selection range
 */
function unmark_selection_as_ner(editor){
	if(editor.somethingSelected() && editor.getSelection().trim() != ""){
		var selected_range = editor.get_selected_range();
		/**
		 * Handle intersections with all previously recorded marks in the range
		 * ** Clear all previous marks in the same range
		 * ** TODO : Handler markers at the beginning and end of selection
		 */
		var marksInRange = editor.findMarks(selected_range.from, selected_range.to)
		$(marksInRange).each(function(){
			if( $(this).get(0).className == "translators-desk-marker-ner"){
				$(this).get(0).clear();
			}
		})
	}
}

/**
 * Collects NER markers from all across the text
 */
function collectNERMarkers(editor){
	return editor.getAllMarks()
}

/**
 * Collects all differente types of markers from all across the text
 */
function collectMarkers(editor){
	return collectNERMarkers(editor);
}

/**
 * Collects all metadata available with the editor as a json object
 */
function collectTextMetaDataBeforeSave(editor){
	return {
		markers: collectMarkers(editor),
		history: editor.getHistory()
	}
}

/**
 * Sets up Translators Desk MenuItem Handlers
 */
function setupTranslatorsDeskMenuItemHandlers(){

	/**
	 * Click Handler for Undo Button
	 */
	$(".td-menu-item-undo").click(function(d){
		var editor = get_corresponding_editor_from_menu_item($(this));
		editor.execCommand("undoSelection");
	});

	/**
	 * Click Handler for Redo Button
	 */
	$(".td-menu-item-redo").click(function(d){
		var editor = get_corresponding_editor_from_menu_item($(this));
		editor.execCommand("redoSelection");
	})
}

function intitContextualMenus(){
	context.init({
		fadeSpeed: 100,
		filter: function ($obj){},
		above: true	,
		compress: false
	});
}

/**
 * Sets up all event handlers required for TextSelection events
 */
function setupTextSelectionHandlers(){
	$(editors).each(function(){
		/**
		 * TODO:
		 * Look for a proper event listener to detect end of text selection
		 * currently using ` mouseup` to detect end of selection.
		 */
		var editor = $(this).get(0);
		$(".codemirror_block").mouseup(function(){

			if(editor.somethingSelected() && editor.getSelection().trim() != ""){
				// Something will be selected during a mouseup event only
				// if it is the end of a text selection
				// if a `mousedown` followed by a `mouseup` is done while a
				// range of text is selected, it will be automatically deselected
				currentContextMenuTargetEditor = editor;
				context.attach(".CodeMirror-selectedtext", ContextMenuObjects.translators_desk_selected_text_menu);
			}
		});
	});
}

/**
 * Input Methods specific functions for the editor
 */

/**
 * Return the textarea corresponding to an editor instance
 */
function get_editor_textarea(editor){
	return $(editor.getWrapperElement()).find("textarea");
}

/**
 * get the imeselector instance corresponding to an editor instance
 * @param  {[type]} editor [description]
 * @return {[type]}        [description]
 */
function get_editor_ime_selector(editor){
	return get_editor_textarea(editor).data("imeselector");
}

/**
 * Sets editor language when passed the editor instance and language code
 */
function set_editor_language(editor,language_code){
	get_editor_ime_selector(editor).selectLanguage(language_code);
	//Setup the default input method as configured
	if(TranslatorsDeskGlobals.default_input_methods(language_code)){
		set_editor_input_method(editor, TranslatorsDeskGlobals.default_input_methods(language_code))
	}
}

/**
 * Sets the editor input method when passed the editor instance and input method
 */
function set_editor_input_method(editor, input_method){
	get_editor_ime_selector(editor).selectIM(input_method);
}

/**
 * Returns the language list select object
 */
function get_editor_language_menu(editor){
	var editor_id = get_editor_id(editor);
	return $("#codemirror_menu_"+editor_id).find(".translators_desk_language_list");
}

/**
 * builds and renders the language list corresponding to an editor instance and the given options
 */
function build_language_list_menu(editor, options){
	console.log("Building language list menu");

	$.each($.ime.languages, function(key, value){
		if(options.languages){
			//If a default list of languages is submitted, then render only those
			if(options.languages.indexOf(key) != -1){
				$('<option>').val(key).text(value.autonym).appendTo(get_editor_language_menu(editor));
			}
		}else{
			//If a default list of languages is not submitted, then render all the available languages
			$('<option>').val(key).text(value.autonym).appendTo(get_editor_language_menu(editor));
		}
	})
	$(".translators_desk_language_list").change(function(){
		set_editor_language(get_corresponding_editor_from_menu_item($(this)), $(this).val());
	});
}

/**
 * Holds the default input methods for supported languages
 */
TranslatorsDeskGlobals.default_input_methods = function(language){
	switch(language){
		case 'hi':
			return 'hi-phonetic'
		case 'pa':
			return 'pa-phonetic'
		case 'te':
			return 'te-transliteration'
		case 'ta':
			return 'ta-transliteration'
		case 'ur':
			return 'ur-phonetic'
		default:
			return false
	}
}

/**
 * Instantiates jquery.ime for regional language inputs
 */
function setupInputMethods(editor, options){
	build_language_list_menu(editor, options)
	if(!options.imePath){
		options.imePath = "/static/libs/jquery.ime/";
	}
	console.log(options.languages);
	get_editor_textarea(editor).ime({
		languages: options.languages,
		imePath: options.imePath
	});
	if(options.defaultLanguage){
		set_editor_language(editor, options.defaultLanguage);
		get_editor_language_menu(editor).val(options.defaultLanguage);

		if(options.defaultIM){
			set_editor_input_method(editor, options.defaultIM);
		}
	}
}
/**
 * Updates the internal data store with the latest word at the cursor
 */
function updateCurrentWord(editor){
	editor.currentWordRange = editor.findWordAt(editor.getCursor());
	editor.currentWord = editor.getRange(editor.currentWordRange.anchor, editor.currentWordRange.head);
}
/**
 * Setups up Events Handlers for content change in the editor
 */
function setupCodeMirrorInputReadEventHandlers(){
	$(editors).each(function(){
		$(this).get(0).on("inputRead", function(editor){
			updateCurrentWord(editor);
			CodeMirror.commands.translators_desk_aspell(editor);
		})
	})
}

/**
 * Sets up Socket IO Event Handlers
 */
function setupSocketEventHandlers(){
	//Test Echo Event receiver
    socket.on('translanslators_desk_echo_response', function(msg) {
        console.log('Received: ' + msg.data );
    });
}

/**
 * Sets up SocketIO connection
 */
function setupSocketIO(){
	var namespace = "/td";
    window.socket = io.connect('http://' + document.domain + ':' + location.port + namespace);

    socket.on('connect', function() {
                console.log("Translators Desk Socket Connected !!");
            });
    setupSocketEventHandlers();
}

$(document).ready(function(){
	setupSocketIO();
	setupTranslatorsDeskMenuItemHandlers();
	intitContextualMenus();
	setupTextSelectionHandlers();
	setupCodeMirrorInputReadEventHandlers();
	setupInputMethods(editors[0],
								{
									defaultLanguage: "hi",
									defaultIM: "hi-phonetic",
									languages: ['en','hi','pa', 'te', 'ta', 'ur']
								}
		);

	$("#translators_desk_translate_btn").click(function(){
		var editor = get_corresponding_editor_from_menu_item($(this));
		//Meta data about the text collected and ready to be saved
		console.log(collectTextMetaDataBeforeSave(editor));
	});
})<commit_msg>Updates editor's current word record on cursor change event<commit_after>/**
 * holds references to all available CodeMirror instances on the page
 * @type {Array}
 */
var editors = [];
var currentEditor = null;
var TranslatorsDeskGlobals = {}

var currentContextMenuTargetEditor = null;
var ContextMenuObjects = {};
ContextMenuObjects.translators_desk_ner_submenu =
	[
		{
			header: 'NER'
		},
		{
			text: ' Add NER markers',
			action: function(e){
				window.spm = e;
				var editor = currentContextMenuTargetEditor;
				mark_selection_as_ner(editor);
			}
		},
		{
			text: ' Clear NER markers',
			action: function(e){
				window.spm = e;
				var editor = currentContextMenuTargetEditor;
				unmark_selection_as_ner(editor);
			}
		}
	]
ContextMenuObjects .translators_desk_selected_text_menu = ContextMenuObjects.translators_desk_ner_submenu;

/**
 * Instantiates all available codemirror_blocks as CodeMirror instances
 */

$(".codemirror_block").each(function(){
	var editor = CodeMirror($(this)[0], {
	  value: "",
	  mode: "simple",
	  theme: 'eclipse',
	  lineNumbers: true,
	  lineWrapping: true,
	  styleSelectedText: true,
	  dragDrop: false,
	  extraKeys: {"Ctrl-Space": "translators_desk_aspell"}
	});

	/**
	 * Dynamically adds `get_selected_range` function to the editor instance
	 */
	editor.get_selected_range = function() {
	  return { from: editor.getCursor(true), to: editor.getCursor(false) };
	};
	editors.push(editor);
})

/**
 * Configures Per-language auto-suggestion query thresholds
 */

TranslatorsDeskGlobals.word_length_query_threshold = {}
TranslatorsDeskGlobals.word_length_query_threshold['en'] = 3
TranslatorsDeskGlobals.word_length_query_threshold['hi'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['pa'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['te'] = 2
TranslatorsDeskGlobals.word_length_query_threshold['ta'] = 2

var editor_word_length_query_threshold;
/**
 * Instantiates Translators Desk Word Suggesstion
 */
CodeMirror.commands.translators_desk_aspell = function(editor) {
	editor_word_length_query_threshold = TranslatorsDeskGlobals.word_length_query_threshold[get_editor_language_menu(editor).val()]
	if(editor.currentWord && editor_word_length_query_threshold && editor.currentWord.trim().length > editor_word_length_query_threshold ){
		//Only consider words of length more than 3
		socket.emit("translanslators_desk_get_word_suggesstion",
					{
						data: editor.currentWord,
						lang: get_editor_language_menu(editors[0]).val()
					})

		var socket_response_listener = function(data){
			// TODO : The removelistener code is not working now
			// Fix this
			// Remove corresponding event listener
			socket.removeListener("translanslators_desk_get_word_suggesstion_"+$.md5(editor.currentWord.toLowerCase()), socket_response_listener )

			//Display the hint
			editor.showHint({
								hint: CodeMirror.hint.translators_desk_aspell,
								translators_desk_aspell_suggesstions: JSON.parse(data)
							});
		}
		socket.on("translanslators_desk_get_word_suggesstion_"+$.md5(editor.currentWord.toLowerCase()), socket_response_listener);
	}
}

/**
 * Gets the editor_id corresponding to a translators desk menu item
 * @param  menu_item jquery_selector_object
 * @return int
 */
function get_corresponding_editor_id_from_menu_item(menu_item){
	return $(menu_item).parents(".codemirror_menu").attr("td-editor-id");
}
/**
 * Gets the editor object corresponding to a translators desk menu item
 * @param  menu_item jquery_selector_object
 * @return CodeMirror editor object
 */
function get_corresponding_editor_from_menu_item(menu_item){
	var editor_id = parseInt(get_corresponding_editor_id_from_menu_item(menu_item));
	return editors[editor_id-1];
}

/**
 * Gets the editor_id corresponding to a translators desk codemirror element
 * @param  codemirror_element jquery_selector_object
 * @return int
 */
function get_corresponding_editor_id(codemirror_element){
	return $(codemirror_element).parents(".codemirror_block").attr("td-editor-id");
}
/**
 * Gets the editor object corresponding to a translators desk codemirror element
 * @param  codemirror_element jquery_selector_object
 * @return CodeMirror editor object
 */
function get_corresponding_editor(codemirror_element){
	var editor_id = parseInt(get_corresponding_editor_id(codemirror_element));
	return editors[editor_id-1];
}

function get_editor_id(editor){
	return $(editor.getWrapperElement()).parents(".codemirror_block").attr("td-editor-id");
}

/**
 * Marks a selected range as NER
 */
function mark_selection_as_ner(editor){
	if(editor.somethingSelected() && editor.getSelection().trim() != "" ){
		var selected_range = editor.get_selected_range();

		//Unmark all previous marks in that range
		unmark_selection_as_ner(editor);

		var selection = editor.markText(selected_range.from,
			selected_range.to,
			{
				className: "translators-desk-marker-ner",
				addToHistory: true,
			});
	}else{
			//TODO : Add handler for NER click on no selection
			console.log("You have not selected text yet");
	}
}
/**
 * Removes ner-marks from a selection range
 */
function unmark_selection_as_ner(editor){
	if(editor.somethingSelected() && editor.getSelection().trim() != ""){
		var selected_range = editor.get_selected_range();
		/**
		 * Handle intersections with all previously recorded marks in the range
		 * ** Clear all previous marks in the same range
		 * ** TODO : Handler markers at the beginning and end of selection
		 */
		var marksInRange = editor.findMarks(selected_range.from, selected_range.to)
		$(marksInRange).each(function(){
			if( $(this).get(0).className == "translators-desk-marker-ner"){
				$(this).get(0).clear();
			}
		})
	}
}

/**
 * Collects NER markers from all across the text
 */
function collectNERMarkers(editor){
	return editor.getAllMarks()
}

/**
 * Collects all differente types of markers from all across the text
 */
function collectMarkers(editor){
	return collectNERMarkers(editor);
}

/**
 * Collects all metadata available with the editor as a json object
 */
function collectTextMetaDataBeforeSave(editor){
	return {
		markers: collectMarkers(editor),
		history: editor.getHistory()
	}
}

/**
 * Sets up Translators Desk MenuItem Handlers
 */
function setupTranslatorsDeskMenuItemHandlers(){

	/**
	 * Click Handler for Undo Button
	 */
	$(".td-menu-item-undo").click(function(d){
		var editor = get_corresponding_editor_from_menu_item($(this));
		editor.execCommand("undoSelection");
	});

	/**
	 * Click Handler for Redo Button
	 */
	$(".td-menu-item-redo").click(function(d){
		var editor = get_corresponding_editor_from_menu_item($(this));
		editor.execCommand("redoSelection");
	})
}

function intitContextualMenus(){
	context.init({
		fadeSpeed: 100,
		filter: function ($obj){},
		above: true	,
		compress: false
	});
}

/**
 * Sets up all event handlers required for TextSelection events
 */
function setupTextSelectionHandlers(){
	$(editors).each(function(){
		/**
		 * TODO:
		 * Look for a proper event listener to detect end of text selection
		 * currently using ` mouseup` to detect end of selection.
		 */
		var editor = $(this).get(0);
		$(".codemirror_block").mouseup(function(){

			if(editor.somethingSelected() && editor.getSelection().trim() != ""){
				// Something will be selected during a mouseup event only
				// if it is the end of a text selection
				// if a `mousedown` followed by a `mouseup` is done while a
				// range of text is selected, it will be automatically deselected
				currentContextMenuTargetEditor = editor;
				context.attach(".CodeMirror-selectedtext", ContextMenuObjects.translators_desk_selected_text_menu);
			}
		});
	});
}

/**
 * Input Methods specific functions for the editor
 */

/**
 * Return the textarea corresponding to an editor instance
 */
function get_editor_textarea(editor){
	return $(editor.getWrapperElement()).find("textarea");
}

/**
 * get the imeselector instance corresponding to an editor instance
 * @param  {[type]} editor [description]
 * @return {[type]}        [description]
 */
function get_editor_ime_selector(editor){
	return get_editor_textarea(editor).data("imeselector");
}

/**
 * Sets editor language when passed the editor instance and language code
 */
function set_editor_language(editor,language_code){
	get_editor_ime_selector(editor).selectLanguage(language_code);
	//Setup the default input method as configured
	if(TranslatorsDeskGlobals.default_input_methods(language_code)){
		set_editor_input_method(editor, TranslatorsDeskGlobals.default_input_methods(language_code))
	}
}

/**
 * Sets the editor input method when passed the editor instance and input method
 */
function set_editor_input_method(editor, input_method){
	get_editor_ime_selector(editor).selectIM(input_method);
}

/**
 * Returns the language list select object
 */
function get_editor_language_menu(editor){
	var editor_id = get_editor_id(editor);
	return $("#codemirror_menu_"+editor_id).find(".translators_desk_language_list");
}

/**
 * builds and renders the language list corresponding to an editor instance and the given options
 */
function build_language_list_menu(editor, options){
	console.log("Building language list menu");

	$.each($.ime.languages, function(key, value){
		if(options.languages){
			//If a default list of languages is submitted, then render only those
			if(options.languages.indexOf(key) != -1){
				$('<option>').val(key).text(value.autonym).appendTo(get_editor_language_menu(editor));
			}
		}else{
			//If a default list of languages is not submitted, then render all the available languages
			$('<option>').val(key).text(value.autonym).appendTo(get_editor_language_menu(editor));
		}
	})
	$(".translators_desk_language_list").change(function(){
		set_editor_language(get_corresponding_editor_from_menu_item($(this)), $(this).val());
	});
}

/**
 * Holds the default input methods for supported languages
 */
TranslatorsDeskGlobals.default_input_methods = function(language){
	switch(language){
		case 'hi':
			return 'hi-phonetic'
		case 'pa':
			return 'pa-phonetic'
		case 'te':
			return 'te-transliteration'
		case 'ta':
			return 'ta-transliteration'
		case 'ur':
			return 'ur-phonetic'
		default:
			return false
	}
}

/**
 * Instantiates jquery.ime for regional language inputs
 */
function setupInputMethods(editor, options){
	build_language_list_menu(editor, options)
	if(!options.imePath){
		options.imePath = "/static/libs/jquery.ime/";
	}
	console.log(options.languages);
	get_editor_textarea(editor).ime({
		languages: options.languages,
		imePath: options.imePath
	});
	if(options.defaultLanguage){
		set_editor_language(editor, options.defaultLanguage);
		get_editor_language_menu(editor).val(options.defaultLanguage);

		if(options.defaultIM){
			set_editor_input_method(editor, options.defaultIM);
		}
	}
}
/**
 * Updates the internal data store with the latest word at the cursor
 */
function updateCurrentWord(editor){
	editor.currentWordRange = editor.findWordAt(editor.getCursor());
	editor.currentWord = editor.getRange(editor.currentWordRange.anchor, editor.currentWordRange.head);
}

function setupCursorActivityHandlers(){
	$(editors).each(function(){
		var editor = $(this).get(0).on("cursorActivity", function(editor){
			updateCurrentWord(editor);
		})
	});
}
/**
 * Setups up Events Handlers for content change in the editor
 */
function setupCodeMirrorInputReadEventHandlers(){
	$(editors).each(function(){
		$(this).get(0).on("inputRead", function(editor){
			CodeMirror.commands.translators_desk_aspell(editor);
		})
	})
}

/**
 * Sets up Socket IO Event Handlers
 */
function setupSocketEventHandlers(){
	//Test Echo Event receiver
    socket.on('translanslators_desk_echo_response', function(msg) {
        console.log('Received: ' + msg.data );
    });
}

/**
 * Sets up SocketIO connection
 */
function setupSocketIO(){
	var namespace = "/td";
    window.socket = io.connect('http://' + document.domain + ':' + location.port + namespace);

    socket.on('connect', function() {
                console.log("Translators Desk Socket Connected !!");
            });
    setupSocketEventHandlers();
}

$(document).ready(function(){
	setupSocketIO();
	setupTranslatorsDeskMenuItemHandlers();
	intitContextualMenus();
	setupTextSelectionHandlers();
	setupCursorActivityHandlers();
	setupCodeMirrorInputReadEventHandlers();
	setupInputMethods(editors[0],
								{
									defaultLanguage: "hi",
									defaultIM: "hi-phonetic",
									languages: ['en','hi','pa', 'te', 'ta', 'ur']
								}
		);

	$("#translators_desk_translate_btn").click(function(){
		var editor = get_corresponding_editor_from_menu_item($(this));
		//Meta data about the text collected and ready to be saved
		console.log(collectTextMetaDataBeforeSave(editor));
	});
})<|endoftext|>


<commit_before>(function($){
// Ok, let's do eeet

ACTIVE_NODE_BG_COLOR = '#B7D7E8';
RECENTLY_MOVED_COLOR = '#FFFF00';
RECENTLY_MOVED_FADEOUT = '#FFFFFF';
ABORT_COLOR = '#EECCCC';
DRAG_LINE_COLOR = '#AA00AA';

RECENTLY_FADE_DURATION = 2000;

// This is the basic Node class, which handles UI tree operations for each 'row'
var Node = function(elem) {
    var $elem = $(elem);
    var node_id = $elem.attr('node');
    var parent_id = $elem.attr('parent');
    var level = parseInt($elem.attr('level'));
    var children_num = parseInt($elem.attr('children-num'));
    return {
        elem: elem,
        $elem: $elem,
        node_id: node_id,
        parent_id: parent_id,
        level: level,
        has_children: function() {
            return children_num > 0;
        },
        node_name: function() {
            // Returns the text of the node
            return $elem.find('th a:not(.collapse)').text();
        },
        is_collapsed: function() {
            return $elem.find('a.collapse').hasClass('collapsed');
        },
        children: function() {
            return $('tr[parent=' + node_id + ']');
        },
        collapse: function() {
            // For each children, hide it's childrens and so on...
            $.each(this.children(), function(){
                var node = new Node(this);
                node.collapse();
            }).hide();
            // Swicth class to set the proprt expand/collapse icon
            $elem.find('a.collapse').removeClass('expanded').addClass('collapsed');
        },
        parent_node: function() {
            // Returns a Node object of the parent
            return new Node($('tr[node=' + parent_id + ']', $elem.parent())[0]);
        },
        expand: function() {
            // Display each kid (will display in collapsed state)
            this.children().show();
            // Swicth class to set the proprt expand/collapse icon
            $elem.find('a.collapse').removeClass('collapsed').addClass('expanded');

        },
        toggle: function() {
            if (this.is_collapsed()) {
                this.expand();
            } else {
                this.collapse();
            }
        },
        clone: function() {
            return $elem.clone();
        }
    }
}

$(document).ready(function(){

    // begin csrf token code
    // Taken from http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
    $('html').ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
            // Only send the token to relative URLs i.e. locally.
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    });
    // end csrf token code

    // Don't activate drag or collapse if GET filters are set on the page
    if ($('#has-filters').val() === "1") {
        return;
    }

    $body = $('body');

    // Activate all rows for drag & drop
    // then bind mouse down event
    $('td.drag-handler span').addClass('active').bind('mousedown', function(evt) {
        $ghost = $('

');
        $drag_line = $('

');
        $ghost.appendTo($body);
        $drag_line.appendTo($body);

        var stop_drag = function() {
            $ghost.remove();
            $drag_line.remove();
            $body.enableSelection().unbind('mousemove').unbind('mouseup');
            node.elem.removeAttribute('style');
        }

        // Create a clone create the illusion that we're moving the node
        var node = new Node($(this).closest('tr')[0]);
        cloned_node = node.clone();
        node.$elem.css({
            'background': ACTIVE_NODE_BG_COLOR
        });

        $targetRow = null;
        as_child = false;

        // Now make the new clone move with the mouse
        $body.disableSelection().bind('mousemove', function(evt2) {
            $ghost.html(cloned_node).css({  // from FeinCMS :P
                'opacity': .8,
                'position': 'absolute',
                'top': evt2.pageY,
                'left': evt2.pageX-30,
                'width': 600
            });
            // Iterate through all rows and see where am I moving so I can place
            // the drag line accordingly
            rowHeight = node.$elem.height();
            $('tr', node.$elem.parent()).each(function(index, element) {
                $row = $(element);
                rtop = $row.offset().top;
                // The tooltop will display whether I'm droping the element as
                // child or sibling
                $tooltip = $drag_line.find('span');
                $tooltip.css({
                    'left': node.$elem.width() - $tooltip.width(),
                    'height': rowHeight,
                });
                node_top = node.$elem.offset().top;
                // Check if you are dragging over the same node
                if (evt2.pageY >= node_top && evt2.pageY <= node_top + rowHeight) {
                    $targetRow = null;
                    $tooltip.text('Abort');
                    $drag_line.css({
                        'top': node_top,
                        'height': rowHeight,
                        'borderWidth': 0,
                        'opacity': 0.8,
                        'backgroundColor': ABORT_COLOR
                    });
                } else
                // Check if mouse is over this row
                if (evt2.pageY >= rtop && evt2.pageY <= rtop + rowHeight/2) {
                    // The mouse is positioned on the top half of a $row
                    $targetRow = $row;
                    as_child = false;
                    $drag_line.css({
                        'left': node.$elem.offset().left,
                        'width': node.$elem.width(),
                        'top': rtop,
                        'borderWidth': '5px',
                        'height': 0,
                        'opacity': 1
                    });
                    $tooltip.text('As Sibling');
                } else if (evt2.pageY >= rtop + rowHeight/2 && evt2.pageY <= rtop + rowHeight) {
                    // The mouse is positioned on the bottom half of a row
                    $targetRow = $row;
                    target_node = new Node($targetRow[0]);
                    if (target_node.is_collapsed()) {
                        target_node.expand();
                    }
                    as_child = true;
                    $drag_line.css({
                        'top': rtop,
                        'left': node.$elem.offset().left,
                        'height': rowHeight,
                        'opacity': 0.4,
                        'width': node.$elem.width(),
                        'borderWidth': 0,
                        'backgroundColor': DRAG_LINE_COLOR
                    });
                    $tooltip.text('As child');
                }
            });
        }).bind('mouseup', function() {
            if ($targetRow !== null) {
                target_node = new Node($targetRow[0]);
                if (target_node.node_id !== node.node_id) {
                    /*alert('Insert node ' + node.node_name() + ' as child of: '
                    + target_node.parent_node().node_name() + '\n and sibling of: '
                        + target_node.node_name());*/
                    // Call $.ajax so we can handle the error
                    // On Drop, make an XHR call to perform the node move
                    $.ajax({
                        url: window.MOVE_NODE_ENDPOINT,
                        type: 'POST',
                        data: {
                            node_id: node.node_id,
                            parent_id: target_node.parent_id,
                            sibling_id: target_node.node_id,
                            as_child: as_child?1:0
                        },
                        complete: function(req, status) {
                            // http://stackoverflow.com/questions/1439895/add-a-hash-with-javascript-to-url-without-scrolling-page/1439910#1439910
                            node.$elem.remove();
                            window.location.hash = 'node-' + node.node_id;
                            window.location.reload();
                        },
                        error: function(req, status, error) {
                            // On error (!200) also reload to display
                            // the message
                            node.$elem.remove();
                            window.location.hash = 'node-' + node.node_id;
                            window.location.reload();
                        }
                    });
                }
            }
            stop_drag();
        }).bind('keyup', function(kbevt) {
            // Cancel drag on escape
            if (kbevt.keyCode === 27) {
                stop_drag();
            }
        });
    });

    $('a.collapse').click(function(){
        var node = new Node($(this).closest('tr')[0]); // send the DOM node, not jQ
        node.toggle();
        return false;
    });
    var hash = window.location.hash;
    // This is a hack, the actual element's id ends in '-id' but the url's hash
    // doesn't, I'm doing this to avoid scrolling the page... is that a good thing?
    if (hash) {
        $(hash + '-id').animate({
            backgroundColor: RECENTLY_MOVED_COLOR
        }, RECENTLY_FADE_DURATION, function() {
            $(this).animate({
                backgroundColor: RECENTLY_MOVED_FADEOUT
            }, RECENTLY_FADE_DURATION, function(){
                this.removeAttribute('style');
            });
        });
    }
});
})(django.jQuery);

// http://stackoverflow.com/questions/190560/jquery-animate-backgroundcolor/2302005#2302005
(function(d){d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(f,e){d.fx.step[e]=function(g){if(!g.colorInit){g.start=c(g.elem,e);g.end=b(g.end);g.colorInit=true}g.elem.style[e]="rgb("+[Math.max(Math.min(parseInt((g.pos*(g.end[0]-g.start[0]))+g.start[0]),255),0),Math.max(Math.min(parseInt((g.pos*(g.end[1]-g.start[1]))+g.start[1]),255),0),Math.max(Math.min(parseInt((g.pos*(g.end[2]-g.start[2]))+g.start[2]),255),0)].join(",")+")"}});function b(f){var e;if(f&&f.constructor==Array&&f.length==3){return f}if(e=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)){return[parseInt(e[1]),parseInt(e[2]),parseInt(e[3])]}if(e=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)){return[parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55]}if(e=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}if(e=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}if(e=/rgba\(0, 0, 0, 0\)/.exec(f)){return a.transparent}return a[d.trim(f).toLowerCase()]}function c(g,e){var f;do{f=d.curCSS(g,e);if(f!=""&&f!="transparent"||d.nodeName(g,"body")){break}e="backgroundColor"}while(g=g.parentNode);return b(f)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]}})(django.jQuery);
<commit_msg>Marked javascript strings for i18n.<commit_after>(function($){
// Ok, let's do eeet

ACTIVE_NODE_BG_COLOR = '#B7D7E8';
RECENTLY_MOVED_COLOR = '#FFFF00';
RECENTLY_MOVED_FADEOUT = '#FFFFFF';
ABORT_COLOR = '#EECCCC';
DRAG_LINE_COLOR = '#AA00AA';

RECENTLY_FADE_DURATION = 2000;

// This is the basic Node class, which handles UI tree operations for each 'row'
var Node = function(elem) {
    var $elem = $(elem);
    var node_id = $elem.attr('node');
    var parent_id = $elem.attr('parent');
    var level = parseInt($elem.attr('level'));
    var children_num = parseInt($elem.attr('children-num'));
    return {
        elem: elem,
        $elem: $elem,
        node_id: node_id,
        parent_id: parent_id,
        level: level,
        has_children: function() {
            return children_num > 0;
        },
        node_name: function() {
            // Returns the text of the node
            return $elem.find('th a:not(.collapse)').text();
        },
        is_collapsed: function() {
            return $elem.find('a.collapse').hasClass('collapsed');
        },
        children: function() {
            return $('tr[parent=' + node_id + ']');
        },
        collapse: function() {
            // For each children, hide it's childrens and so on...
            $.each(this.children(), function(){
                var node = new Node(this);
                node.collapse();
            }).hide();
            // Swicth class to set the proprt expand/collapse icon
            $elem.find('a.collapse').removeClass('expanded').addClass('collapsed');
        },
        parent_node: function() {
            // Returns a Node object of the parent
            return new Node($('tr[node=' + parent_id + ']', $elem.parent())[0]);
        },
        expand: function() {
            // Display each kid (will display in collapsed state)
            this.children().show();
            // Swicth class to set the proprt expand/collapse icon
            $elem.find('a.collapse').removeClass('collapsed').addClass('expanded');

        },
        toggle: function() {
            if (this.is_collapsed()) {
                this.expand();
            } else {
                this.collapse();
            }
        },
        clone: function() {
            return $elem.clone();
        }
    }
}

$(document).ready(function(){

    // begin csrf token code
    // Taken from http://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
    $('html').ajaxSend(function(event, xhr, settings) {
        function getCookie(name) {
            var cookieValue = null;
            if (document.cookie && document.cookie != '') {
                var cookies = document.cookie.split(';');
                for (var i = 0; i < cookies.length; i++) {
                    var cookie = jQuery.trim(cookies[i]);
                    // Does this cookie string begin with the name we want?
                    if (cookie.substring(0, name.length + 1) == (name + '=')) {
                        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                        break;
                    }
                }
            }
            return cookieValue;
        }
        if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
            // Only send the token to relative URLs i.e. locally.
            xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
        }
    });
    // end csrf token code

    // Don't activate drag or collapse if GET filters are set on the page
    if ($('#has-filters').val() === "1") {
        return;
    }

    $body = $('body');

    // Activate all rows for drag & drop
    // then bind mouse down event
    $('td.drag-handler span').addClass('active').bind('mousedown', function(evt) {
        $ghost = $('

');
        $drag_line = $('

');
        $ghost.appendTo($body);
        $drag_line.appendTo($body);

        var stop_drag = function() {
            $ghost.remove();
            $drag_line.remove();
            $body.enableSelection().unbind('mousemove').unbind('mouseup');
            node.elem.removeAttribute('style');
        }

        // Create a clone create the illusion that we're moving the node
        var node = new Node($(this).closest('tr')[0]);
        cloned_node = node.clone();
        node.$elem.css({
            'background': ACTIVE_NODE_BG_COLOR
        });

        $targetRow = null;
        as_child = false;

        // Now make the new clone move with the mouse
        $body.disableSelection().bind('mousemove', function(evt2) {
            $ghost.html(cloned_node).css({  // from FeinCMS :P
                'opacity': .8,
                'position': 'absolute',
                'top': evt2.pageY,
                'left': evt2.pageX-30,
                'width': 600
            });
            // Iterate through all rows and see where am I moving so I can place
            // the drag line accordingly
            rowHeight = node.$elem.height();
            $('tr', node.$elem.parent()).each(function(index, element) {
                $row = $(element);
                rtop = $row.offset().top;
                // The tooltop will display whether I'm droping the element as
                // child or sibling
                $tooltip = $drag_line.find('span');
                $tooltip.css({
                    'left': node.$elem.width() - $tooltip.width(),
                    'height': rowHeight,
                });
                node_top = node.$elem.offset().top;
                // Check if you are dragging over the same node
                if (evt2.pageY >= node_top && evt2.pageY <= node_top + rowHeight) {
                    $targetRow = null;
                    $tooltip.text(gettext('Abort'));
                    $drag_line.css({
                        'top': node_top,
                        'height': rowHeight,
                        'borderWidth': 0,
                        'opacity': 0.8,
                        'backgroundColor': ABORT_COLOR
                    });
                } else
                // Check if mouse is over this row
                if (evt2.pageY >= rtop && evt2.pageY <= rtop + rowHeight/2) {
                    // The mouse is positioned on the top half of a $row
                    $targetRow = $row;
                    as_child = false;
                    $drag_line.css({
                        'left': node.$elem.offset().left,
                        'width': node.$elem.width(),
                        'top': rtop,
                        'borderWidth': '5px',
                        'height': 0,
                        'opacity': 1
                    });
                    $tooltip.text(gettext('As Sibling'));
                } else if (evt2.pageY >= rtop + rowHeight/2 && evt2.pageY <= rtop + rowHeight) {
                    // The mouse is positioned on the bottom half of a row
                    $targetRow = $row;
                    target_node = new Node($targetRow[0]);
                    if (target_node.is_collapsed()) {
                        target_node.expand();
                    }
                    as_child = true;
                    $drag_line.css({
                        'top': rtop,
                        'left': node.$elem.offset().left,
                        'height': rowHeight,
                        'opacity': 0.4,
                        'width': node.$elem.width(),
                        'borderWidth': 0,
                        'backgroundColor': DRAG_LINE_COLOR
                    });
                    $tooltip.text(gettext('As child'));
                }
            });
        }).bind('mouseup', function() {
            if ($targetRow !== null) {
                target_node = new Node($targetRow[0]);
                if (target_node.node_id !== node.node_id) {
                    /*alert('Insert node ' + node.node_name() + ' as child of: '
                    + target_node.parent_node().node_name() + '\n and sibling of: '
                        + target_node.node_name());*/
                    // Call $.ajax so we can handle the error
                    // On Drop, make an XHR call to perform the node move
                    $.ajax({
                        url: window.MOVE_NODE_ENDPOINT,
                        type: 'POST',
                        data: {
                            node_id: node.node_id,
                            parent_id: target_node.parent_id,
                            sibling_id: target_node.node_id,
                            as_child: as_child?1:0
                        },
                        complete: function(req, status) {
                            // http://stackoverflow.com/questions/1439895/add-a-hash-with-javascript-to-url-without-scrolling-page/1439910#1439910
                            node.$elem.remove();
                            window.location.hash = 'node-' + node.node_id;
                            window.location.reload();
                        },
                        error: function(req, status, error) {
                            // On error (!200) also reload to display
                            // the message
                            node.$elem.remove();
                            window.location.hash = 'node-' + node.node_id;
                            window.location.reload();
                        }
                    });
                }
            }
            stop_drag();
        }).bind('keyup', function(kbevt) {
            // Cancel drag on escape
            if (kbevt.keyCode === 27) {
                stop_drag();
            }
        });
    });

    $('a.collapse').click(function(){
        var node = new Node($(this).closest('tr')[0]); // send the DOM node, not jQ
        node.toggle();
        return false;
    });
    var hash = window.location.hash;
    // This is a hack, the actual element's id ends in '-id' but the url's hash
    // doesn't, I'm doing this to avoid scrolling the page... is that a good thing?
    if (hash) {
        $(hash + '-id').animate({
            backgroundColor: RECENTLY_MOVED_COLOR
        }, RECENTLY_FADE_DURATION, function() {
            $(this).animate({
                backgroundColor: RECENTLY_MOVED_FADEOUT
            }, RECENTLY_FADE_DURATION, function(){
                this.removeAttribute('style');
            });
        });
    }
});
})(django.jQuery);

// http://stackoverflow.com/questions/190560/jquery-animate-backgroundcolor/2302005#2302005
(function(d){d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(f,e){d.fx.step[e]=function(g){if(!g.colorInit){g.start=c(g.elem,e);g.end=b(g.end);g.colorInit=true}g.elem.style[e]="rgb("+[Math.max(Math.min(parseInt((g.pos*(g.end[0]-g.start[0]))+g.start[0]),255),0),Math.max(Math.min(parseInt((g.pos*(g.end[1]-g.start[1]))+g.start[1]),255),0),Math.max(Math.min(parseInt((g.pos*(g.end[2]-g.start[2]))+g.start[2]),255),0)].join(",")+")"}});function b(f){var e;if(f&&f.constructor==Array&&f.length==3){return f}if(e=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(f)){return[parseInt(e[1]),parseInt(e[2]),parseInt(e[3])]}if(e=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(f)){return[parseFloat(e[1])*2.55,parseFloat(e[2])*2.55,parseFloat(e[3])*2.55]}if(e=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(f)){return[parseInt(e[1],16),parseInt(e[2],16),parseInt(e[3],16)]}if(e=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(f)){return[parseInt(e[1]+e[1],16),parseInt(e[2]+e[2],16),parseInt(e[3]+e[3],16)]}if(e=/rgba\(0, 0, 0, 0\)/.exec(f)){return a.transparent}return a[d.trim(f).toLowerCase()]}function c(g,e){var f;do{f=d.curCSS(g,e);if(f!=""&&f!="transparent"||d.nodeName(g,"body")){break}e="backgroundColor"}while(g=g.parentNode);return b(f)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]}})(django.jQuery);
<|endoftext|>