(function($) { $.fn.redraw = function() { return this.map(function(){ this.offsetTop; return this; }); }; $.fn.prepareSlideX = function(callback) { return this.map(function(){ $(this).css({width: this.scrollWidth, overflow: 'hidden'}); return this; }).one('transitionend', function(){ $(this).css({width: '', overflow: ''}); callback && callback.call(this); }).redraw(); }; $.fn.prepareSlideY = function(callback) { return this.map(function(){ $(this).css({height: this.scrollHeight, overflow: 'hidden'}); return this; }).one('transitionend', function(){ $(this).css({height: '', overflow: ''}); callback && callback.call(this); }).redraw(); }; $.fn.animOff = function(this_el) { if (this_el) { return this.css('transition', 'none').redraw(); } return this.addClass('no-transition').redraw(); }; $.fn.animOn = function(this_el) { if (this_el) { return this.redraw().css('transition', ''); } return this.redraw().removeClass('no-transition'); }; $.fn.fadeShow = function() { return this.removeClass('ohide'); }; $.fn.fadeHide = function() { return this.addClass('ohide'); }; $.fn.isFadeHidden = function() { return this.hasClass('ohide'); }; $.fn.isFixed = function() { return this.parents().map(function(){ return $(this).css('position'); }).get().indexOf('fixed') != -1; }; $.fn.focusAndSelectAll = function() { var range = document.createRange(), field, sel; if (field = this.get(0)) { field.focus(); range.selectNodeContents(field); sel = window.getSelection(); sel.removeAllRanges(); sel.addRange(range); } return this; }; $.fn.fadeToggle = function(state) { if (state === true || state === false) { state = !state; } return this.toggleClass('ohide', state); }; $.fn.slideShow = function(callback) { return this.prepareSlideY(callback).removeClass('shide'); }; $.fn.slideHide = function(callback) { if (callback == 'remove') { callback = function(){ $(this).remove(); }; } return this.prepareSlideY(callback).addClass('shide'); }; $.fn.slideXShow = function(callback) { return this.prepareSlideX(callback).removeClass('sxhide'); }; $.fn.slideXHide = function(callback) { if (callback == 'remove') { callback = function(){ $(this).remove(); }; } return this.prepareSlideX(callback).addClass('sxhide'); }; $.fn.isSlideHidden = function() { return this.hasClass('shide'); }; $.fn.slideToggle = function(state, callback) { if (state === true || state === false) { state = !state; } return this.prepareSlideY(callback).toggleClass('shide', state); }; $.fn.highlight = function(delay) { var $this = this; $this.addClass('highlight'); setTimeout(function() { $this.removeClass('highlight'); }, delay); return $this; }; $.fn.hasField = function(name) { return this.first().map(function() { if (this.tagName == 'FORM') { if (this[name]) { return true; } return $('.input[data-name]', this).filter(function() { return ($(this).attr('data-name') == name); }).size() > 0; } return false; }).get(0) || false; }; $.fn.field = function(name) { return this.first().map(function() { if (this.tagName == 'FORM') { if (this[name]) { return this[name]; } return $('.input[data-name]', this).filter(function() { return ($(this).attr('data-name') == name); }).get(0); } }); }; $.fn.reset = function(val) { return this.each(function() { if (this.tagName == 'FORM') { this.reset(); $('.input[data-name]', this).each(function() { $(this).text($(this).attr('data-value')).trigger('input'); }); } }); }; $.fn.defaultValue = function(val) { if (typeof val !== 'undefined') { return this.each(function() { if (this.tagName == 'TEXTAREA' || this.tagName == 'INPUT') { this.defaultValue = val; } else { $(this).attr('data-value', val); } }); } return this.first().map(function() { if (this.tagName == 'TEXTAREA' || this.tagName == 'INPUT') { return this.defaultValue || ''; } else { return $(this).attr('data-value') || ''; } }).get(0) || ''; }; $.fn.value = function(val) { if (typeof val !== 'undefined') { return this.each(function() { if (this.tagName == 'TEXTAREA' || this.tagName == 'INPUT') { this.value = val; } else { $(this).text(val).trigger('input'); } }); } return this.first().map(function() { if (this.tagName == 'TEXTAREA' || this.tagName == 'INPUT') { return this.value || ''; } else { return $(this).text() || ''; } }).get(0) || ''; }; $.fn.values = function(val) { if (typeof val !== 'undefined') { return this.value(val); } return this.map(function() { if (this.tagName == 'TEXTAREA' || this.tagName == 'INPUT') { return this.value || ''; } else { return $(this).text() || ''; } }).get() || []; }; })(jQuery); function getBR() { if (window._brHTML) return window._brHTML; return window._brHTML = $('

').html(); } function cleanHTML(value) { return value.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/\n/g, getBR()); } function cleanRE(value) { return value.replace(/[|\\{}()[\]^$+*?.]/g, "\\$&"); } function wrapHighlight(value, highlight, wrap_tag, prefix_only) { value = cleanHTML(value); if (highlight) { var pattern = cleanRE(cleanHTML(highlight)); if (prefix_only) { pattern = '^' + pattern; } value = value.replace(new RegExp(pattern, 'gi'), '$&<\/strong>'); } if (wrap_tag) { value = value.replace(TOKEN_REGEX, '$&'); } return value; } function wrapSize(size) { if (size < 1024) { return size + ' B'; } else if (size < 1048576) { return (Math.round(size * 10 / 1024.0) / 10) + ' KB'; } else if (size < 1073741824) { return (Math.round(size * 10 / 1048576.0) / 10) + ' MB'; } else { return (Math.round(size * 10 / 1073741824.0) / 10) + ' GB'; } } function dataUrlToBlob(url) { try { var match = null; if (match = url.match(/^data:(image\/gif|image\/jpe?g|image\/png|video\/mp4);base64,(.*)$/)) { var type = match[1], b64 = match[2]; var binary = atob(b64); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], {type: type}); } } catch (e) {} return false; } function urlToDataUrl(url, callback) { var img = new Image(); img.crossOrigin = 'anonymous'; img.onload = function() { try { var canvas = document.createElement('canvas'); canvas.width = this.naturalWidth; canvas.height = this.naturalHeight; canvas.getContext('2d').drawImage(this, 0, 0); callback(canvas.toDataURL()); } catch (e) { callback(false); } }; img.onerror = function() { callback(false); }; img.src = url; } function parseStr(value) { var arr = value.split('&'), kv, str, result = {}; for (var i = 0; i < arr.length; i++) { kv = arr[i].split('='); result[decodeURIComponent(kv[0])] = decodeURIComponent(kv[1]); } return result; } function validateSlug(value) { if (value.match(/[A-Za-z0-9\-_=]{16,32}/)) { return true; } return false; } function stopImmediatePropagation(e) { e.stopImmediatePropagation(); } function preventDefault(e) { e.preventDefault(); } var Editor = { init: function(options) { Aj.onLoad(function(state) { state.fileContent = options.content; state.thumbKeys = options.thumb_keys || {}; state.builtinSlug = options.builtin_slug || ''; state.canEdit = options.can_edit || false; state.options = options; var mac = /Mac/.test(navigator.platform) || /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent); $source_code = $('.th-theme-source-code'); state.editor = CodeMirror.fromTextArea($source_code.get(0), { tabSize: 2, lineWrapping: true, styleActiveLine: {nonEmpty: true}, viewportMargin: Infinity, readOnly: !state.canEdit, cursorBlinkRate: state.canEdit ? 530 : -1, colorpicker: { mode: state.canEdit ? 'edit' : 'view', hideDelay: 5000, outputFormat: 'hex', included_token: ['valcol', 'val'], colorSets: [ { name : 'Custom', edit: true, colors: options.colorset }, ] }, extraKeys: mac ? { 'Cmd-S': Editor.cmSave, 'Tab': Editor.cmTab, 'Shift-Tab': Editor.cmShiftTab } : { 'Ctrl-S': Editor.cmSave, 'Tab': Editor.cmTab, 'Shift-Tab': Editor.cmShiftTab } }); state.editor.setValue(options.content); state.editor.on('changes', Editor.onContentChange); $('.th-theme-source-code-wrap').fadeShow(); $('.th-theme-save-btn').on('click', Editor.eSaveTheme); $('.th-theme-create-btn').on('click', Editor.eCreateThemeFormat); $(document).on('click.curPage', '.th-theme-import-btn', Editor.eImportFile); $(document).on('click.curPage', '.file-upload', stopImmediatePropagation); $(document).on('change.curPage', '.file-upload', Editor.eSelectImportFile); Aj.onBeforeUnload(function (e) { if (!Aj.state.editor) return false; var fileContent = Aj.state.editor.getValue(); if (Aj.state.fileContent !== false && Aj.state.fileContent != fileContent) { return 'You have unsaved changes, you really want to leave this page?'; } return false; }); Editor.onContentChange(); $(window).on('scroll', Editor.onScroll); }); Aj.onUnload(function(state) { state.editor.off('changes', Editor.onContentChange); $('.th-theme-save-btn').off('click', Editor.eSaveTheme); $('.th-theme-create-btn').off('click', Editor.eCreateThemeFormat); $(window).off('scroll', Editor.onScroll); }); }, cmSave: function(cm) { Editor.saveTheme(); }, cmTab: function(cm) { var cursor = cm.getCursor('to'), line = cursor.line, ch = cursor.ch; var looped = false; while (true) { var str = cm.getLine(line).split('//')[0]; var match = /:(\s*)(.*\S|)\s*$/.exec(str), val_index = null, val_len = 0; if (match) { val_index = match.index + 1 + match[1].length; val_len = match[2].length; if (ch < val_index || ch == val_index && val_len > 0) { cm.doc.setSelection({line: line, ch: val_index + val_len}, {line: line, ch: val_index}); if (Aj.state.canEdit) { var val = match[2], col_val = Editor.parseColor(val); if (col_val) { cm.state.colorpicker.popup_color_picker(); } else { cm.state.colorpicker.close_color_picker(); } } break; } } ++line; ch = 0; if (line >= cm.lineCount()) { if (looped) break; looped = true; line = 0; } } }, cmShiftTab: function(cm) { var cursor = cm.getCursor('from'), line = cursor.line, ch = cursor.ch; var looped = false; while (true) { var str = cm.getLine(line).split('//')[0]; var match = /:(\s*)(.*\S|)\s*$/.exec(str), val_index = null, val_len = 0; if (match) { val_index = match.index + 1 + match[1].length; val_len = match[2].length; if (ch > val_index + val_len || ch == val_index + val_len && val_len > 0) { cm.doc.setSelection({line: line, ch: val_index + val_len}, {line: line, ch: val_index}); if (Aj.state.canEdit) { var val = match[2], col_val = Editor.parseColor(val); if (col_val) { cm.state.colorpicker.popup_color_picker(); } else { cm.state.colorpicker.close_color_picker(); } } break; } } --line; ch = Infinity; if (line < 0) { if (looped) break; looped = true; line = cm.lineCount() - 1; } } }, onScroll: function() { var scrollTop = $(window).scrollTop(); $('body').toggleClass('header-btn-oshow', scrollTop > 50); }, onContentChange: function() { Editor.redrawThumb($('.th-theme-thumb')); Editor.updateColumns(); }, updateColumns: function() { var key_max_len = 30, key_max_el = null; $('.cm-keycol').each(function() { var key_len = $(this).text().length; if (key_len > key_max_len) { key_max_len = key_len; key_max_el = this; } }); if (key_max_el) { key_max_el.style.minWidth = '0px'; key_max_width = key_max_el.offsetWidth; key_max_el.style.minWidth = ''; } else { key_max_width = 230; } var old_style = $('#th-content-style').html(); var new_style = '.cm-keycol{min-width:' + key_max_width + 'px}'; if (new_style != old_style) { $('#th-content-style').html(new_style); } }, parseColor: function(color_value) { if ($.isArray(color_value)) { return color_value; } var color_val = $.trim(color_value), match, r, g, b, a = 1; if (match = color_val.match(/^(rgba?)\(\s*(\d+)\s*,\s*(\d+)\s*\s*,\s*(\d+)\s*(?:,\s*((?:0?\.)?\d+)\s*)?\)/)) { r = parseInt(match[2]); g = parseInt(match[3]); b = parseInt(match[4]); if (match[1] == 'rgba' && match[5]) { a = parseFloat(match[5]); } return [r, g, b, a, match[0]]; } else if (match = color_val.match(/^#?([0-9a-f]{3,8})(?::((?:0?\.)?\d+))?/i)) { var val = match[1], val_len = val.length, sr, sg, sb, sa; if (val_len == 3 || val_len == 4) { sr = val.substr(0, 1); r = parseInt(sr + sr, 16); sg = val.substr(1, 1); g = parseInt(sg + sg, 16); sb = val.substr(2, 1); b = parseInt(sb + sb, 16); if (val_len == 4) { sa = val.substr(3, 1); $a = parseInt(sa + sa, 16) / 255; } } else if (val_len == 6 || val_len == 8) { sr = val.substr(0, 2); r = parseInt(sr, 16); sg = val.substr(2, 2); g = parseInt(sg, 16); sb = val.substr(4, 2); b = parseInt(sb, 16); if (val_len == 8) { sa = val.substr(6, 2); a = parseInt(sa, 16) / 255; } } else { return false; } if ((val_len == 3 || val_len == 6) && match[2]) { a = parseFloat(match[2]); } return [r, g, b, a, match[0]]; } return false; }, formatColor: function(color_value) { var color_arr = Editor.parseColor(color_value); if (!color_arr) { return false; } if (color_arr[3] < 1) { return 'rgba(' + color_arr[0] + ',' + color_arr[1] + ',' + color_arr[2] + ',' + color_arr[3] + ')'; } var color_int = ((color_arr[0] & 255) << 16) | ((color_arr[1] & 255) << 8) | (color_arr[2] & 255); return '#' + ('000000' + color_int.toString(16)).substr(-6); }, parseWallpaperValue(value) { var match, bg_slug, options, arr, result = {}; if (!value) { return result; } if (value == 'builtin') { result.slug = Aj.state.builtinSlug; } else if (match = value.match(/^(?:https?:\/\/)?t\.me\/bg\/(\S+)/i)) { arr = match[1].split('?'); if (match = arr[0].match(/^[0-9a-f]{6}-[0-9a-f]{6}$/i)) { result.gradient = arr[0].split('-'); for (var k = 0; k < result.gradient.length; k++) { result.gradient[k] = Editor.formatColor(result.gradient[k]); } options = arr[1] ? parseStr(arr[1]) : {}; if (options.rotation) { var rot = parseInt(options.rotation); if (rot && rot < 360 && !(rot % 45)) { result.rotation = parseInt(options.rotation); } } } else if (match = arr[0].match(/^[0-9a-f]{6}(~[0-9a-f]{6}){1,3}$/i)) { result.gradient = arr[0].split('~'); for (var k = 0; k < result.gradient.length; k++) { result.gradient[k] = Editor.formatColor(result.gradient[k]); } options = arr[1] ? parseStr(arr[1]) : {}; if (options.rotation) { var rot = parseInt(options.rotation); if (rot && rot < 360 && !(rot % 45)) { result.rotation = parseInt(options.rotation); } } } else if (validateSlug(arr[0])) { result.slug = arr[0]; options = arr[1] ? parseStr(arr[1]) : {}; if (options.bg_color) { if (match = options.bg_color.match(/^[0-9a-f]{6}-[0-9a-f]{6}$/i)) { result.gradient = options.bg_color.split('-'); for (var k = 0; k < result.gradient.length; k++) { result.gradient[k] = Editor.formatColor(result.gradient[k]); } } else if (match = options.bg_color.match(/^[0-9a-f]{6}(~[0-9a-f]{6}){1,3}$/i)) { result.gradient = options.bg_color.split('~'); for (var k = 0; k < result.gradient.length; k++) { result.gradient[k] = Editor.formatColor(result.gradient[k]); } } else { result.color = Editor.formatColor(options.bg_color); } } if (options.intensity) { result.intensity = parseInt(options.intensity); } if (options.rotation) { var rot = parseInt(options.rotation); if (rot && rot < 360 && !(rot % 45)) { result.rotation = parseInt(options.rotation); } } if (options.mode) { result.mode = options.mode; } } else if (arr[0]) { result.color = Editor.formatColor(arr[0]); } } else { result.color = Editor.formatColor(value); } return result; }, formatWallpaperUrl(bg_slug) { return bg_slug ? location.origin + '/bg/' + bg_slug : ''; }, getContentValue: function(content, key) { if (!key) return null; var re = new RegExp('\\b' + cleanRE(key) + '\\s*:\\s*(.*)(?:\n|$)', 'i'); var match = content.match(re); return match && match[1] || null; }, redrawThumb: function($parent, callback) { var fileContent = Aj.state.editor.getValue(); var wallpaper = Editor.parseWallpaperValue(Editor.getContentValue(fileContent, Aj.state.thumbKeys.bg)); var bg_url = Editor.formatWallpaperUrl(wallpaper.slug); var bg_color_val = Editor.formatColor(Editor.getContentValue(fileContent, Aj.state.thumbKeys.bg_color)) || '#6ea8f3'; var bubble_in_val = Editor.formatColor(Editor.getContentValue(fileContent, Aj.state.thumbKeys.bubble_in)) || '#fff'; var bubble_out_val = Editor.formatColor(Editor.getContentValue(fileContent, Aj.state.thumbKeys.bubble_out)) || '#d4f1ff'; if (wallpaper.color) { bg_color_val = wallpaper.color; } else if (wallpaper.gradient) { var bg_grad = $('#bg_gradient', $parent).get(0); if (bg_grad) { bg_grad.setAttribute('gradientTransform', 'rotate(' + (wallpaper.rotation || 0) + ' 0.5 0.5)'); } $('#bg_gradient_color1', $parent).attr('stop-color', wallpaper.gradient[0]); $('#bg_gradient_color2', $parent).attr('stop-color', wallpaper.gradient[1]); bg_color_val = "url('#bg_gradient')"; } if (wallpaper.intensity) { var opacity = Math.max(10, Math.min(wallpaper.intensity, 100)); $('#thumb_bg_image', $parent).attr('opacity', opacity / 100); } else { $('#thumb_bg_image', $parent).attr('opacity', 1); } if (/\bblur\b/i.test(wallpaper.mode || '')) { $('#thumb_bg_image', $parent).attr('filter', 'url(\'#thumb_blur\')'); } else { $('#thumb_bg_image', $parent).attr('filter', ''); } $('#thumb_bg_image', $parent).attr('xlink:href', bg_url); $('#thumb_bg_color', $parent).attr('fill', bg_color_val); $('#thumb_bubble_in', $parent).attr('fill', bubble_in_val); $('#thumb_bubble_out', $parent).attr('fill', bubble_out_val); if (callback) { urlToDataUrl(bg_url, function(bg_url) { if (bg_url) { $('#thumb_bg_image', $parent).attr('xlink:href', bg_url); } callback(); }); } }, prepareThumb: function(callback) { var $svg = $('
'); Editor.redrawThumb($svg, function() { callback($svg.html()); }); }, generateThumb: function(callback) { Editor.prepareThumb(function(svg) { var image = document.createElement('img'); image.src = 'data:image/svg+xml,' + encodeURIComponent(svg); image.addEventListener('load', function imgLoaded() { image.removeEventListener('load', imgLoaded); try { var canvas = document.createElement('canvas'), blob; canvas.width = 296; canvas.height = 184; var ctx = canvas.getContext('2d'); ctx.drawImage(image, 0, 0, canvas.width, canvas.height); if (canvas.toBlob) { canvas.toBlob(callback, 'image/jpeg', 0.92); } else { callback(dataUrlToBlob(canvas.toDataURL('image/jpeg', 0.92))); } } catch (e) {} }); image.addEventListener('error', function imgFailed() { callback(null); }); }); }, eCreateThemeFormat: function(e) { $('.th-container').removeClass('th-no-content'); }, eImportFile: function(e) { if (!Aj.state.canEdit) return; e && e.stopImmediatePropagation(); e && e.preventDefault(); $('').appendTo(this).click(); }, eSelectImportFile: function(e) { if (!Aj.state.canEdit) return; var input = this; var $import_btn = $('.th-theme-import-btn'); var theme_raw = $import_btn.attr('data-theme-raw'); var format = $import_btn.attr('data-format'); var data = new FormData(); var fileContent = Aj.state.editor.getValue(); var theme_name = Editor.getContentValue(fileContent, 'name') || ''; var theme_shortname = Editor.getContentValue(fileContent, 'shortname') || ''; data.append('method', 'importFile'); data.append('theme_name', theme_name); data.append('theme_shortname', theme_shortname); data.append('format', format); data.append('file', input.files[0]); $import_btn.prop('disabled', true); $.ajax(Aj.apiUrl, { type: 'POST', enctype: 'multipart/form-data', data: data, processData: false, contentType: false, cache: false, dataType: 'json', xhrFields: { withCredentials: true }, success: function(result) { $import_btn.prop('disabled', false); if (result._dlog) { $('#dlog').append(result._dlog); } if (result.error) { return showAlert(result.error); } if (result.content) { Aj.state.editor.setValue(result.content); Editor.onContentChange(); $('.th-container').removeClass('th-no-content'); } }, error: function(xhr) { if (xhr.status == 401) { location.href = '/auth'; } else { location.reload(); } } }); }, eSaveTheme: function(e) { e.preventDefault(); Editor.saveTheme(); }, saveTheme: function() { var $save_btn = $('.th-theme-save-btn'); if (Aj.state.saving) { return false; } var content = Aj.state.editor.getValue(); if (!content) { Aj.state.editor.focus(); return false; } var file = new Blob([content], {type: 'text/plain'}); $save_btn.prop('disabled', true); Aj.state.saving = true; Aj.state.savingContent = content; Editor.generateThumb(function (thumb) { Editor.saveThemeRequest(file, thumb); }); return false; }, saveThemeRequest: function(file, thumb, payload) { var $save_btn = $('.th-theme-save-btn'); var theme_raw = $save_btn.attr('data-theme-raw'); var format = $save_btn.attr('data-format'); var data = new FormData(); data.append('method', 'saveTheme'); data.append('theme_raw', theme_raw); data.append('format', format); data.append('content', file, 'content'); data.append('thumb', thumb, 'thumb'); if (payload) { data.append('payload', payload); } $.ajax(Aj.apiUrl, { type: 'POST', enctype: 'multipart/form-data', data: data, processData: false, contentType: false, cache: false, dataType: 'json', xhrFields: { withCredentials: true }, success: function(result) { if (result._dlog) { $('#dlog').append(result._dlog); } if (result.need_pack) { return Editor.packFile(result.need_pack, thumb, result.payload); } $save_btn.prop('disabled', false); Aj.state.saving = false; if (result.error) { return showAlert(result.error); } Aj.state.fileContent = Aj.state.savingContent; var cur_loc = Aj.location(); if (result.slug && cur_loc.pathname != '/theme/' + result.slug) { cur_loc.pathname = '/theme/' + result.slug; return Aj.location(cur_loc.href); } if (result.title) { $('.js-theme-title').html(result.title); } }, error: function(xhr) { if (xhr.status == 401) { location.href = '/auth'; } else { location.reload(); } } }); return false; }, packFile: function(files, thumb, payload) { for (var i = 0; i < files.length; i++) { var file = files[i]; if (file.url) { return JSZipUtils.getBinaryContent(file.url, function(err, data) { if (err) { $('.th-theme-save-btn').prop('disabled', false); Aj.state.saving = false; return showAlert('Can\'t fetch file'); } file.content = data; delete file.url; Editor.packFile(files, thumb, payload); }); } } var zip = new JSZip(); for (var i = 0; i < files.length; i++) { var file = files[i]; zip.file(file.name, file.content, {binary: file.binary}); } zip.generateAsync({ type: 'blob', compression: 'DEFLATE' }).then(function (zip_file) { Editor.saveThemeRequest(zip_file, thumb, payload); }); } };