Roselia-Blog 3.7 & 3.8

An Editing Experience Enhancement

May 20, 2020

见习魔法师

Roselia-Blog 3.7 更新

3.7版本,对于浏览者来说,没有太多的亮点,因为几乎看不见什么显著的变化。 对于在上面写作的人来说,体验变好了。首先的变化是,图片上传功能的回归。说是回归的原因是,Roselia-Blog曾经neo版本就具有了上传图片的功能,后来在Roselia-Blog 2.0的升级中,取消了该功能 毕竟重写了。在这个版本中,终于想到去写一写这个功能了。

首先,最大的变化是弃用了SimpleMDE,因为已经多年没有维护了,改为了API基本一致的EasyMDE。该版本解决了在黑暗模式下,图标颜色无法变化的问题,因此,现在进入编辑页面,不会强制进入浅色模式了。

接下来是增加了图片上传的功能,主要分为三个channel,上传到本站,chevereto和sm.ms。在编辑文章的时候,可以选择相应的channel上传。这次更新取消了通常的上传选择和上传按钮,改为在编辑器中粘贴图片或者拖拽图片来上传,其中的图片将自动转为markdown格式。

在探究编辑器粘贴板的时候,我发现了粘贴板里面可以有多个不同类型的文件,首先必有的是type为text/plain的,作为纯文本。我只需要拦截kind为file的,并且type以image开头的,将其读取之后,发送上传请求即可,最后在编辑器内改变或输入相应的文本即可。

有意思的点是,我发现了VSCode在粘贴文本的时候,会增加一些特殊的metadata,这应该是实现粘贴自动匹配语言的实现方法。

其样本如下:

{
    "version": 1,
    "isFromEmptySelection": false,
    "multicursorText": null,
    "mode": "typescript"
}

isFromEmptySelection 决定了该文本是不是啥都没选的情况下直接点复制而来的

multicursorText 为一个字符串的列表,表示了每一个不同的选择域选了哪些文本。

mode就是我们关心的,决定了语言。因此我们只要去读这个内容,看见了该信息,就自动粘贴为markdown的fenced code即可。

Roselia-Blog 3.8

在3.7发布不久后,3.8就发布了,并不是为了恶意刷版本号,而是因为3.8具有一个breaking change。主要的改动对用户不可见。即,token原本被作为参数传入,现在Roselia-Blog遵循规范,将其放在HTTP Header里面,作为Authentication header。 形如:Authentication: Bearer <token>

这样做的好处是:原本token作为参数,在get请求时有被记录的可能,造成泄漏。 现在,放在header里面,降低了这种可能性。

3.8.1

该版本的改动就是增加了动态预览的功能。在编辑界面时,将会看见类似r{{ icon('preview') }}这样的按钮。在点击后,会弹出新窗口,你可以将该窗口与编辑窗口并列,或者放到新的屏幕上。接下来,你在内容上的改动将实时体现在该窗口上。该功能的实现原理是实时监听localStorage中草稿的变化。一旦监听到变化就重新渲染文章。编辑页面上只监听文章内容的变化,对于文章元信息的改变需要手动点保存草稿,或者等待编辑文章内容时的自动保存。

上述更新其实就是普通的细节更新,作为访客,自然无法发现区别。但是看似简单的东西有别样的内涵一直是Roselia-Blog的设计目标,现在,就是向这个目标迈向的一小步。

体验

如果你拥有Roselia-Blog的账户,而且你愿意尝试,点击按钮尝试新的编辑体验:r{{ (function (w) { var userData = w.JSON.parse(w.localStorage.getItem('loginData')) var upgrade = () => { if (!userData) { sendNotification({ message: 'Sorry, please login.', color: 'error' }) return; } userData.role = userData.role || 1 w.localStorage.setItem('loginData', (w.JSON.stringify(userData))) sendNotification({ message: 'Great! Redirecting you to editing page.', color: 'success' }) w.setTimeout(() => { w.location.href = '/blog/edit' }, 1000); }

    var tryBtn = btn('Try', () => askForAccess('edit-experience', 'New Editing Experience', 'You are invited to try out the new editing experience.').then(upgrade));
    var loginBtn = btn('Login', () => {
        w.sessionStorage.setItem('redirectURL', w.JSON.stringify(w.location.pathname.replace('/blog', '')))
        w.location.href = '/blog/login'
    }, 'warning');
var successBtn = btn('Go Edit', () => {
        w.location.href = '/blog/edit'
    }, 'success')
    if (userData) return userData.role ? successBtn : tryBtn;
    return loginBtn;

})(''.constructor.constructor('return window')()) }}

r{{ changeExtraDisplaySettings({disableSideNavigation: true, blurMainImage: true}) }}