Seditio Source
Root |
./othercms/xenForo 2.2.8/js/xf/code_editor.js
!function($, window, document, _undefined)
{
"use strict";

XF.CodeEditor = XF.Element.newHandler({
options: {
indentUnit: 4,
indentWithTabs: true,
lineNumbers: true,
lineWrapping: false,
autoCloseBrackets: true,
autoCloseTags: null,
mode: null,
config: null,
submitSelector: null,
scrollbarStyle: 'simple'
},

editor: null,
$wrapper: null,

init: function()
{
if (!this.isAdvancedEditorSupported())
{
// textarea is hidden in the template
this.$target.show();
return;
}

// this is checking the parent node because we have css that will force hide this textarea
if (this.$target[0].parentNode.scrollHeight)
{
this.initEditor();
}
else
{
this.$target.oneWithin('toggle:shown overlay:showing tab:shown', XF.proxy(this, 'initEditor'));
}
},

isAdvancedEditorSupported: function()
{
return (XF.browser.os !== 'android');
},

initEditor: function()
{
var $textarea = this.$target,
lang = {},
config = {};

if ($textarea.data('cmInitialized'))
{
return;
}

try
{
config = $.parseJSON(this.options.config);
}
catch (e)
{
config = this.options.config;
}

try
{
lang = $.parseJSON($('.js-codeEditorLanguage').first().html()) || {};
}
catch (e)
{
console.error(e);
lang = {};
}

config = $.extend({
mode: this.options.mode,
indentUnit: this.options.indentUnit,
indentWithTabs: this.options.indentWithTabs,
lineNumbers: this.options.lineNumbers,
lineWrapping: this.options.lineWrapping,
autoCloseBrackets: this.options.autoCloseBrackets,
readOnly: $textarea.prop('readonly'),
autofocus: $textarea.prop('autofocus'),
scrollbarStyle: this.options.scrollbarStyle,
phrases: lang
}, config);

// This might come from the mode config, so only override it if something is set in the options.
// Note that this might be overridden with a language change.
var autoCloseTags = this.options.autoCloseTags;
if (autoCloseTags !== null)
{
config.autoCloseTags = autoCloseTags ? true : false;
}

this.editor = CodeMirror.fromTextArea($textarea.get(0), config);

this.$wrapper = $(this.editor.getWrapperElement());

var classes = $textarea.attr('class').replace(/(^| )input(--[^ ]+)?(?= |$)/g, '$1');

// Sync the textarea classes to CodeMirror
this.$wrapper.addClass(classes).attr('dir', 'ltr');
$textarea.attr('class', '');
this.editor.refresh();

XF.layoutChange();

this.editor.on('keydown', XF.proxy(this, 'keydown'));

var $form = $textarea.closest('form');
$form.on('ajax-submit:before', XF.proxy(this, 'onSubmit'));

$textarea.trigger('code-editor:init', this.editor);

$textarea.data('cmInitialized', true);
},

onSubmit: function(e)
{
this.editor.save();
},

keydown: function(editor, e)
{
// macOS: Cmd + Ctrl + F | other: F11
if ((XF.isMac() && e.metaKey && e.ctrlKey && e.key == 'f')
|| (!XF.isMac() && e.key == 'F11')
)
{
e.preventDefault();

editor.setOption("fullScreen", !editor.getOption("fullScreen"));
}

// Escape (exit full screen)
if (e.key == 'Escape')
{
e.stopPropagation();

if (editor.getOption("fullScreen"))
{
editor.setOption("fullScreen", false);
}
}

// (ctrl|meta)+(s|enter) submits the associated form
if ((e.key == 's' || e.key == 'Enter') && (XF.isMac() ? e.metaKey : e.ctrlKey))
{
e.preventDefault();

var $textarea = $(editor.getTextArea()),
$form = $textarea.closest('form'),
selector = this.options.submitSelector,
$submit = $form.find(selector);

if (selector && $submit.length)
{
$form.find(selector).click();
}
else
{
$form.submit();
}
}
}
});

XF.CodeEditorSwitcherContainer = XF.Element.newHandler({
options: {
switcher: '.js-codeEditorSwitcher',
templateSuffixMode: 0
},

$switcher: null,

editor: null,
loading: false,
xhr: null,

init: function()
{
this.$target.on('code-editor:init', XF.proxy(this, 'initEditor'));
this.$target.on('code-editor:reinit', XF.proxy(this, 'change'));
},

initEditor: function(e, editor)
{
var $switcher = this.$target.find(this.options.switcher);
if (!$switcher.length)
{
console.warn('Switcher container has no switcher: %o', this.$target);
return;
}
this.$switcher = $switcher;

if ($switcher.is('select, :radio'))
{
$switcher.on('change', XF.proxy(this, 'change'));
}
else if ($switcher.is('input:not(:checkbox :radio)'))
{
$switcher.on('blur', XF.proxy(this, 'blurInput'));

// Trigger after a short delay to get the existing template's mode and apply
setTimeout(function()
{
$switcher.trigger('blur');
}, 100);
}
else
{
console.warn('Switcher only works for text inputs, radios and selects.');
return;
}

this.editor = editor;
},

change: function(e)
{
if (!this.editor)
{
return;
}

var language = this.$switcher.find(":selected").val();

this.switchLanguage(language);
},

blurInput: function(e)
{
var language = this.$switcher.val();

if (this.options.templateSuffixMode)
{
language = language.toLowerCase();

if (language.indexOf('.less') > 0)
{
language = 'less';
}
else if (language.indexOf('.css') > 0)
{
language = 'css';
}
else
{
language = 'html';
}
}

this.switchLanguage(language);
},

switchLanguage: function(language)
{
if (this.loading)
{
return;
}

var self = this,
editor = this.editor,
$textarea = $(editor.getTextArea());

editor.save();

if ($textarea.data('lang') == language)
{
return;
}

setTimeout(function()
{
var url;
if ($('html').data('app') == 'public')
{
url = 'index.php?misc/code-editor-mode-loader';
}
else
{
url = 'admin.php?templates/code-editor-mode-loader';
}

self.xhr = XF.ajax('post', XF.canonicalizeUrl(url), {
language: language
}, XF.proxy(self, 'handleAjax')).always(function() { self.loading = false; });
}, 200);
},

handleAjax: function(data)
{
if (data.errors || data.exception)
{
return;
}

if (data.redirect)
{
XF.redirect(data.redirect);
}

var editor = this.editor,
$textarea = $(editor.getTextArea());

XF.setupHtmlInsert(data.html, function($html, container)
{
var mode = '';

if (data.mime)
{
mode = data.mime;
}
else if (data.mode)
{
mode = data.mode;
}

editor.setOption('mode', mode);
$textarea.data('lang', data.language);
$textarea.data('config', JSON.stringify(data.config));
if (data.config)
{
$.each(data.config, function(key, value)
{
editor.setOption(key, value);
});
}
});
}
});

XF.Element.register('code-editor', 'XF.CodeEditor');
XF.Element.register('code-editor-switcher-container', 'XF.CodeEditorSwitcherContainer');
}
(jQuery, window, document);