Visual Studio Code API’da Decorators Kullanımı

Okuma Süresi: 3 dakika

Visual Studio Code, kod editörüne tasarımsal olarak bazı eklemeler veya düzenlemeler için bize Decorator API isminde bir ortam sunmaktadır. Örnek olması açısından Visual Studio Code’da en çok kullanılan eklentilerden biri olan GitLens‘in kod editörüne yaptığı değişikliği gösterebiliriz.

Bu yazımda biz de buna benzer bir eklenti geliştireceğiz. Geliştireceğimiz eklenti o an açık olan dökümanda Console.WriteLine içeren ifadeleri kırmızı arkaplan ve beyaz yazı rengi ile vurgulayacak.

Daha önce Visual Studio Code için eklenti geliştirmemiş olanlar için https://code.visualstudio.com/api/get-started/your-first-extension adresindeki yazıyı okumalarını tavsiye ederim.

Eklenti oluşturmak için terminal ekranımızda aşağıdaki komutu yazmamız gerekmektedir.

yo code

Bu komutu yazdıktan sonra bize bazı sorular sorulacaktır. Geliştirme dili olarak JavaScript‘i, paket yöneticisi olarak olarak ise yarn‘ı seçtim. Gerekli bilgileri girip onayladıktan sonra eklenti projemiz oluşacak ve gerekli paketlerin kurulumları tamamlanacaktır.

İşlemler tamamlandıktan sonra oluşturulan klasörü Visual Studio Code ile açalım.

Eklenti, extension.js dosyasından başlayarak yüklenmeye başlayacaktır. Bunu değiştirmek isterseniz package.json dosyasındaki “main” bölümünü değiştirmeniz gerekmektedir. Biz şimdilik olduğu gibi bırakacağız.

package.json dosyasında geliştireceğimiz eklentinin ismi, açıklaması, kategorisi, geliştirici bilgileri, eklentide kullanılacak olan paketler gibi bilgiler bulunmaktadır. package.json dosyamızın içeriğini aşağıdaki şekilde değiştirelim.

{
  "name": "vscode-highlighter",
  "displayName": "vscode-highlighter",
  "description": "",
  "version": "0.0.1",
  "engines": {
    "vscode": "^1.33.0"
  },
  "categories": [
    "Other"
  ],
  "activationEvents": [
    "onCommand:extension.highlight"
  ],
  "main": "./extension.js",
  "contributes": {
    "commands": [
      {
        "command": "extension.highlight",
        "title": "Highlight"
      }
    ]
  },
  "scripts": {
    "postinstall": "node ./node_modules/vscode/bin/install",
    "test": "node ./node_modules/vscode/bin/test"
  },
  "devDependencies": {
    "typescript": "^3.3.1",
    "vscode": "^1.1.28",
    "eslint": "^5.13.0",
    "@types/node": "^10.12.21",
    "@types/mocha": "^2.2.42"
  }
}

Yaptığımız değişiklik ile Visual Studio Code üzerinden Highlight komutunu verdiğimiz zaman çalışacağınız belirttik.

Şimdi eklentimiz geliştirmeye başlamak için extension.js dosyasını açalım. Bu dosyayı açtığınızda sizi ilk olarak activate ve deactivate fonksiyonları karşılayacaktır.
active fonksiyonu eklenti komutu ilk defa çağrıldığında çalışacaktır.
deactivate fonksiyonu ise eklenti devre dışı bırakıldığı zaman çalışacaktır. Burayı kullanmış olduğunuz kaynakları temizlemek için kullanabilirsiniz.

Şimdi extension.js dosyasını aşağıdaki şekilde değiştirebiliriz.

// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require("vscode");
const editor = vscode.window.activeTextEditor;
let decorationType = vscode.window.createTextEditorDecorationType({
  backgroundColor: "red",
  color: "white"
});
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed

/**
 * @param {vscode.ExtensionContext} context
 */
function activate(context) {
  // Use the console to output diagnostic information (console.log) and errors (console.error)
  // This line of code will only be executed once when your extension is activated
  console.log(
    'Congratulations, your extension "vscode-highlighter" is now active!'
  );

  // The command has been defined in the package.json file
  // Now provide the implementation of the command with  registerCommand
  // The commandId parameter must match the command field in package.json
  let disposable = vscode.commands.registerCommand(
    "extension.highlight",
    function() {
      // The code you place here will be executed every time your command is executed

      let decorationsArray = [];
      let documentContent = editor.document.getText();
      let sourceCodeArr = documentContent.split("\n");

      for (let line = 0; line < sourceCodeArr.length; line++) {
        let text = sourceCodeArr[line];
        let match = /Console\.WriteLine\(".*?"\);/.exec(text);

        if (match !== null &amp;&amp; match.index !== undefined) {
          let range = new vscode.Range(
            new vscode.Position(line, match.index),
            new vscode.Position(line, match.index + match[0].length)
          );

          let decoration = {
            range: range
          };

          decorationsArray.push(decoration);
        }
      }

      editor.setDecorations(decorationType, decorationsArray);
    }
  );

  context.subscriptions.push(disposable);
}
exports.activate = activate;

// this method is called when your extension is deactivated
function deactivate() {}

module.exports = {
  activate,
  deactivate
};

25. satırda Visual Studio Code üzerinden Highlight komutu gönderildiği zaman eklentinin yapacağı işle ilgili bir fonksiyon tanımlıyoruz.

31. satır ile o an açık olan dökümanın içeriğini alıyoruz ve Regular Expression yardımıyla satırın içerisinde Console.WriteLine ifadesini arıyoruz. Eğer eşleşme olursa 5. satırda tanımlamasını yapmış olduğumuz decorator stilini ilgili alana uyguluyoruz. Decorator objesinin veri tipi DecorationOptions‘tır.

DecorationOption hakkında daha detaylı bilgi almak için https://code.visualstudio.com/api/references/vscode-api#DecorationOptions adresini ziyaret edebilirsiniz.

Eklentiyi test etmek için F5 tuşuna basmamız yeterlidir. F5 tuşuna bastıktan sonra ekrana Extension Development Host penceresi gelecektir. Eklentiyi denemek için Extension Development Host’ta F1 tuşuna basınız ve Highlight yazarak Enter tuşuna basınız. Döküman içerinde Console.WriteLine ifadesi varsa eklenti gerekli olan işlemi gerçekleştirecektir.

Yazıda bahsedilen eklentinin kaynak kodlarına https://github.com/mennan/vscode-decorator-sample adresinden erişebilirsiniz.

JavaScript’te Seçilmiş Metindeki Seçimi Kaldırmak

Okuma Süresi: 1 dakikaJavaScript’te input bir alanda olan seçili metindeki seçimi kaldırmak için aşağıdaki yöntemden faydalanabiliriz.

if (window.getSelection) {
    window.getSelection().removeAllRanges();
} else if (document.selection) {
    document.selection.empty();
}

window.getSelection Internet Explorer 9+ ve diğer tarayıcılar tarafından desteklenmektedir. document.selection ise Internet Explorer 8 ve altı tarayıcılar tarafından desteklenmektedir.

Kaynak: https://www.thewebflash.com/select-or-deselect-text-inside-an-element-using-js/

Tarayıcıda Sekme Değiştirmenin Algılanması

Okuma Süresi: 1 dakikaMerhabalar,

Tarayıcılarda bir sekmeden başka bir sekmeye geçişi Page Visibility API sayesinde anlayabiliriz. visibilityState özelliğinde sekmenin durumu tutulmaktadır. Örnek olarak aşağıdaki kodu inceleyebiliriz:

document.addEventListener("visibilitychange", function() {
  console.log(document.visibilityState);
});

Sekme değişikliklerini visibilitychange olayı yakalamaktadır. visibilityState özelliği aşağıdaki değerleri almaktadır:

  • visible: Tarayıcı sekme aktiftir ve tarayıcı penceresi simge durumuna küçültülmemiştir.
  • hidden: Tarayıcı sekmesi aktif değildir, sekme değiştirilmiştir veya tarayıcı penceresi simge durumuna küçültülmüştür.

Kaynaklar:

https://www.w3.org/TR/page-visibility/
https://developer.mozilla.org/en-US/docs/Web/Events/visibilitychange
https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

Bootstrap Popover Eklentisinin Ekran Görünümüne Göre Konumlanması

Okuma Süresi: 1 dakikaBootstrap’in Popover eklentisini kullanırken tarayıcının ekran boyutlarında herhangi bir değişim olduğunda açılan Popover ekranda düzgün bir şekilde konumlanmamaktadır. Örneğin Popover’ın placement özelliğini top olarak atarsanız tarayıcı ekranını aşağı doğru kaydırdığınızda veya ekran boyutunu değiştirdiğinizde Popover ekranın dışında kalacaktır.


Bu sorunu önlemek için placement özelliğini aşağıdaki şekilde düzenlememiz yeterlidir.

var options = {
    placement: function (context, source) {
        var position = $(source).position();

        if (position.left > 515) {
            return "left";
        }

        if (position.left < 515) {
            return "right";
        }

        if (position.top < 110){
            return "bottom";
        }

        return "top";
    }
};
$(".popover-tooltip").popover(options);

Çalışan örneği aşağıdaki gibidir:


Kaynak: http://stackoverflow.com/a/12656175

TinyMCE ile Formatter Kullanımı

Okuma Süresi: 1 dakikaTinyMCE’de Formatter basit bir şekilde istediğimiz biçimleri uygulamamızı veya kaldırmamıza yarar.

Örnek olarak TinyMCE editöründe seçmiş olduğumuz alanı ins veya del etiketleri arasına alacak ve kaldır düğmesine bastığımızda ise bu biçimleri kaldıracak.

Varsayılan olarak gelen init fonksiyonumuzu aşağıdaki şekilde değiştirelim:

tinymce.init({
    selector: "textarea",
    plugins: [
        "advlist autolink lists link image charmap print preview anchor",
        "searchreplace visualblocks code fullscreen",
        "insertdatetime media table contextmenu paste"
    ],
    toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
    formats: {
         removed: { inline: 'del', 'classes': 'deleted' },
         added: { inline: 'ins', 'classes': 'inserted' }
       }
});

formats özelliğinde istediğimiz kadar yeni biçimler ekleyebiliriz. Bu örnekte removed ve added isminde biçimler ekledik. inline değeri ile hangi elementi kullanarak biçimlendireceğini, classes özelliği ile de elemente class vermiş olduk.

Editörde seçili olan alana bu biçimleri uygulayabilmek veya kaldırabilmek için apply ve remove fonksiyonları kullanılır. apply fonksiyonu seçili alana biçimi uygular, remove fonksiyonu ise seçili alanda uygulanmış bir biçim var ise bu biçimi kaldırır. Her iki fonksiyonda tek bir parametre almaktadır. Parametre olarak formats alanında tanımlamış olduğunuz ismi vermeniz yeterlidir.

Örnek ekran görüntüsü aşağıdaki gibidir.
TinyMCE FormatterYazmış olduğumuz tüm kod aşağıdaki gibidir.

<script type="text/javascript">
tinymce.init({
    selector: "textarea",
    plugins: [
        "advlist autolink lists link image charmap print preview anchor",
        "searchreplace visualblocks code fullscreen",
        "insertdatetime media table contextmenu paste"
    ],
    toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
    formats: {
        removed: { inline: 'del', 'classes': 'deleted' },
        added: { inline: 'ins', 'classes': 'inserted' }
    }
});
</script>

<form method="post" action="dump.php">
    <textarea name="content"></textarea>
</form>
<a href="#" class="add" onclick="tinymce.activeEditor.formatter.apply('added');return false;">ekle</a>
<a href="#" class="remove" onclick="tinymce.activeEditor.formatter.apply('removed');return false;">sil</a>

TinyMCE’nin formatter hakkında daha detaylı bilmek almak ve fonksiyon listesine gitmek için buraya tıklayabilirsiniz.

Yazdığımız kodların bulunduğu örnek sayfaya gitmek için buraya tıklayabilirsiniz.

Regular Expressions’da Türkçe Karakter Problemi

Okuma Süresi: 1 dakikaBir projede Regular Expressions ile geçen metinleri \w pattern’ı ile almaya çalışmıştım. Ancak \w pattern’ı Türkçe karakterleri seçmemekteydi. İnternette yaptığım kısa bir araştırmada aşağıdaki pattern’ı buldum ve test ettiğimde metindeki tüm karakterleri seçebildiğini gördüm.

^\p{L}+$

Bu pattern’la rahatlıkla tüm karakterleri seçebilirsiniz.

TinyMCE Character Encoding

Okuma Süresi: 1 dakikaTinyMCE editöründe varsayılan olarak girilen metinler &nbsp; gibi encode edilerek kaydedilir. Bu ayarı değiştirmek için init fonksiyonunda entity_encoding değerini değiştirmeniz gerekmektedir.

tinymce.init({
        ...
        entity_encoding : "raw"
});

entity_encoding özelliği 3 adet değer almaktadır. Bunlar named, numeric ve raw‘dır.

named değeriyle girilen karakterler otomatik olarak &nbsp; gibi HTML olarak encode edilmektedir.

numeric değeriyle girilen karakterler otomatik olarak &#160; gibi encode edilmektedir.

raw değeriyle ise girilen karakterler olduğu biçimde kaydedilmektedir.

 

Bu konu hakkında daha detaylı bilgi almak için aşağıdaki sayfayı ziyaret edebilirsiniz:

http://www.tinymce.com/wiki.php/Configuration:entity_encoding

TinyMCE’de Custom Button Ekleme

Okuma Süresi: 1 dakikaTinyMCE editöründe bazen varsayılan gelen eklentiler yeterli gelmeyebilir. Bu örneğimizde TinyMCE editörüne tablo hücrelerine kenarlık veren bir menü ekleyeceğiz.

TinyMCE editörünün init kodu aşağıdaki şekildedir:

tinymce.init({
        selector: selector,
        plugins: [
            "advlist autolink lists link image charmap print preview anchor",
            "searchreplace visualblocks code fullscreen",
            "insertdatetime media table paste textcolor tinyfilemanager.net wordcount"
        ],
        toolbar: "insertfile undo redo | styleselect | hucrekenarligi | fontselect | fontsizeselect | forecolor backcolor | bold italic | pastetext | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
        language: "tr_TR",
        fontsize_formats: "8pt 9pt 10pt 11pt 12pt 26pt 36pt",
        forced_root_block: false,
        content_css: cssPath,
        setup: function (ed) {
            //Hücre kenarlığı menüsü
            ed.addButton('hucrekenarligi', {
                type: 'menubutton',
                text: 'Hücre Kenarlığı',
                icon: false,
                menu: [
                    {
                        text: 'Sol', onclick: function () {
                            AddClass("borderLeft");
                        }
                    },
                    {
                        text: 'Sağ', onclick: function () {
                            AddClass("borderRight");
                        }
                    },
                    {
                        text: 'Üst', onclick: function () {
                            AddClass("borderTop");
                        }
                    },
                    {
                        text: 'Alt', onclick: function () {
                            AddClass("borderBottom");
                        }
                    },
                    {
                        text: 'Tümü', onclick: function () {
                            RemoveClasses();
                            AddClass("borderAll");
                        }
                    },
                    {
                        text: 'Temizle', onclick: function () {
                            RemoveClasses();
                        }
                    }
                ]
            });

            function AddClass(className)
            {
                var element = ed.dom.getParent(ed.selection.getNode(), 'td');

                if (!ed.dom.hasClass(element, className))
                    ed.dom.addClass(element, className);
                else
                    ed.dom.removeClass(element, className);
            }

            function RemoveClasses() {
                var element = ed.dom.getParent(ed.selection.getNode(), 'td');

                ed.dom.removeClass(element, "borderLeft");
                ed.dom.removeClass(element, "borderRight");
                ed.dom.removeClass(element, "borderTop");
                ed.dom.removeClass(element, "borderBottom");
                ed.dom.removeClass(element, "borderAll");
            }
        }
    });

Custom button ekleme işlemlerine setup fonksiyonunun içinde başlanmaktadır. addButton fonksiyonu TinyMCE editörü üzerine bir buton eklemektedir. addButton fonksiyonun aldığı ilk parametre menümüz için vereceğimiz benzersiz bir isim olmalıdır. Bu vereceğimiz ismi toolbar özelliğinde kullanacağız.

type değeri olarak menubutton verdiğimizden dolayı ekranda menü şeklinde gözükecektir. Sayfayı çalıştırdığımızda editörümüz aşağıdaki şekilde gözükecektir.

TinyMCE Custom Button

SignalR ile Gerçek Zamanlı Web Uygulamaları

Okuma Süresi: 1 dakikaSignalR, WebSocket protokolünü kullanarak gerçek zamanlı uygulamalar geliştirebileceğimiz bir kütüphanedir. Bugün basit bir sohbet uygulaması yapacağız.

Şimdi bir tane ASP.NET projesi açıp Package Manager Console’dan aşağıdaki komutu girerek SignalR için gerekli dosyaları projemize ekleyelim. (Package Manager Console’a ulaşmak için View->Other Windows -> Package Manager Console menüsünü kullanabilirsiniz.)

Install-Package Microsoft.AspNet.SignalR

Projemize bir sınıf ekleyelim ve aşağıdaki kodları yazalım.

public class ChatHub : Hub
    {
        public void SendMessage(string message)
        {
            Clients.All.sendMessage(message);
        }
    }

Burada yazdığımız kodda sisteme bağlı tüm kullanıcılara yazılan mesajı iletiyoruz. Sunucu tarafındaki kodlama bu kadardır. Şimdi istemci tarafında kodlamaya başlıyoruz.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="SignalRExample.Default" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" src="Scripts/jquery-1.6.4.min.js"></script>
    <script type="text/javascript" src="Scripts/jquery.signalR-2.0.2.min.js"></script>
    <script src='<%: ResolveClientUrl("~/signalr/hubs") %>'></script>
    <script type="text/ecmascript">
        $(function () {
            var chatHub = $.connection.chatHub;

            chatHub.client.receiveMessage = function (message) {
                $(".message").append(message + "<br>");
            };

            function SendMessage() {
                var message = $(".messageText").val();

                if (message != "" && message != null) {
                    chatHub.server.sendMessage(message);
                }
            }

            $(".send").click(function (e) {
                SendMessage();
            });

            $.connection.hub.start();
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
        <input type="text" class="messageText" /><input type="button" class="send" value="Gönder" />
        <div class="message">
        </div>
    </form>
</body>
</html>

Javascript’te yazdığımız kodları tek tek açıklyalım:

  • var chatHub = $.connection.chatHub; satırı ile Hub sınımıfımızın JavaScript kısmında erişebilmek için yazdık. Sınıfımızın ismi Javascript tarafında camel case olarak yazılmıştır. Eğer pascal case veya başka bir adlandırma istersen sınıfımıza [HubName(“ChatHub”)] şeklinde yazabilirsiniz.
  • chatHub.client.receiveMessage satırı ile sunucu tarafında hub tetiklendiğinde çalışacak olan metotdur. Biz burada tetiklendiğinde div içerisine mesajı yazmaktayız.
  • chatHub.server.sendMessage(message); satırı ile sunucu tarafında bulunan SendMessage metodunu çağırıyoruz.
  • $.connection.hub.start(); satırı ile sayfamız yüklendiğinde hub’ın çalışmasını sağlıyoruz.

Kodumuzu derleyip iki farklı tarayıcı ekranında test edince aşağıdaki gibi bir ekran görüntüsü çıkmaktadır:

SignalR ile gerçek zamanlı web uygulamaları

Örnek projenin kodlarını indirmek için tıklayınız.