воскресенье, 30 сентября 2012 г.

Добавление авто-подписи к каждому сообщению на blogspot

В одном своем блоге, который я использую как платформу для опубликования снимков различных объектов (своеобразный клипарт) мне захотелось добавить авто-подпись для всех опубликованных постов. В этой подписи я хотел еще раз упомянуть о том, что фотографии свободны и бесплатны для использования.

В blogspot можно создать шаблон, который используется при создании новых сообщений. Но если вы когда-нибудь захотите изменить авто-подпись, придется править ВСЕ сообщения вручную. Других стандартных способов для решения этой проблемы я не нашел и .. изобрел свой :)

Для этого было решено воспользоваться JavaScript для динамического изменения DOM (Document Object Model) страницы. JavaScript можно добавить на блог как гаджет в его дизайнере:



Подсмотрев код HTML блога установил, что все посты блога заключены в элемент DIV с классом "post-body entry-content". Этого абсолютно достаточно знать, что бы как я, не зная JavaScript (лишь смутные представления) при помощи поисковика накодить следующий скрипт:

<script type='text/javascript'>
  // Тест, что DIV элементы скриптом находятся:
  // var posts = document.getElementsByClassName("post-body entry-content");
  // document.write("Posts: " + posts.length);

  var posts = document.getElementsByClassName("post-body entry-content");
  for (var i=0; i<posts.length; i++) {
    newDiv = document.createElement("div");

    // a) Содержимое DIV можно наполнить так:
    // newLine1 = document.createTextNode("Этот текстовый элемент создан при помощи createTextNode()");
    // newDiv.appendChild(newLine1);

    // b) но мы воспользуемся другим способом: newDiv.innerHTML = '<li>text</li>';
    str = "<span style='font-size: smaller;'>Это первая строка HTML-кода.</span><BR/><span style='font-size: smaller;'>Вторая строка.</span>";
    newDiv.innerHTML = str;

    // Добавим созданный DIV после DIV-сообщения.
    // К сожалению, не существует insertAfter-функции, поэтому эмулируем ее с помощью "parentElement" и "nextSibling":
    posts[i].parentElement.insertBefore(newDiv, posts[i].nextSibling);
  }
</script>


* This source code was highlighted with Source Code Highlighter.


Название в окне настроек гаджета я оставил пустым - теперь о наличии скрипта можно только догадываться.


Результат вы можете посмотреть на моем клипарт-блоге

Ссылки по теме:
Document Object Model (http://en.wikipedia.org/wiki/Document_Object_Model)
document.getElementsByClassName (https://developer.mozilla.org/en-US/docs/DOM/document.getElementsByClassName)
Adding elements to the DOM (http://www.javascriptkit.com/javatutors/dom2.shtml)

понедельник, 24 сентября 2012 г.

Автоматическое изменение размеров FlowLayoutPanel в XtraLayoutControl (DevExpress)


[FlowLayoutPanel with autosize in XtraLayoutControl]

Работая с библиотекой элементов управления для WinForms от DevExpress в ходе практики накопилась небольшая тележка различных решений, обходных путей и просто интересных подходов. Со временем планирую их здесь опубликовать. Ну а пока, покажу, как я реализовал автоматическое изменение размеров FlowLayoutPanel в XtraLayoutControl, так чтобы все элементы, помещенные в FlowLayoutPanel, были всегда видны.

На рисунках отображен уже конечный результат, которого я хотел добиться:






XtraLayoutControl отлично управляет размерами и расположениями “своих” элементов управления из библиотеки DevExpress, но совершено не справляется со стандартными элементами управления, к которым относится FlowLayoutPanel. Дело в том, что XtraLayoutControl взаимодействует с элементами своеобразным образом и требует от элементов реализации специфичных интерфейсов. В нашем случае достаточно использовать интерфейс IXtraResizableControl, который я реализовал в унаследованном от панели классе:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraLayout;
using System.Drawing;
using DevExpress.Utils.Controls;

namespace WindowsFormsApplication9
{
    public class MyFlowLayoutPanel : FlowLayoutPanel, IXtraResizableControl
    {
        public MyFlowLayoutPanel() { // ctor
            
        }

        LayoutControl rootLayoutControl = null;
        LayoutControlItem parentControlItem = null;

        protected override void OnHandleCreated(EventArgs e) {
            base.OnHandleCreated(e);

            if (System.ComponentModel.LicenseManager.UsageMode == System.ComponentModel.LicenseUsageMode.Designtime)
                return;

            LayoutControl parent = this.Parent as LayoutControl;
            if (parent != null) {

                this.rootLayoutControl = parent;
                this.parentControlItem = FindItemByContentControl(parent.Root, this);

                CalcAndUpdateSize();
                this.rootLayoutControl.Resize += (x, y) => { CalcAndUpdateSize(); };
                this.ControlAdded += (x, y) => { CalcAndUpdateSize(); };
                this.ControlRemoved += (x, y) => { CalcAndUpdateSize(); };
            }
        }

        void layoutControl_Changing(object sender, EventArgs e) {
            CalcAndUpdateSize();
        }

        // REM. http://www.devexpress.com/Support/Center/p/Q396747.aspx (Hot to find a conatner LayoutcontrolItem of a control)
        LayoutControlItem FindItemByContentControl(LayoutControlGroup layoutGroup, Control contentControl) {

            foreach (BaseLayoutItem baseLI in layoutGroup.Items) {
                LayoutControlItem lci = baseLI as LayoutControlItem;
                if (lci != null && lci.Control == contentControl)
                    return lci;

                LayoutControlGroup lcg = baseLI as LayoutControlGroup;
                if (lcg != null)
                    return FindItemByContentControl(lcg, contentControl);
            }
                
            return null;
        }


        private void CalcAndUpdateSize() {
            if (parentControlItem == null || parentControlItem.ViewInfo == null) return;

            this.MaximumSize = new Size(parentControlItem.ViewInfo.ClientArea.Width, 0);
            RaiseSizeChanged();
        }

        #region IXtraResizableControl Member

        event EventHandler ChangedCore;
        event EventHandler IXtraResizableControl.Changed {
            add { ChangedCore += value; }
            remove { ChangedCore -= value; }
        }

        protected void RaiseSizeChanged() {
            if (ChangedCore != null) ChangedCore(this, EventArgs.Empty);
        }

        bool IXtraResizableControl.IsCaptionVisible { get { return false; } }

        Size IXtraResizableControl.MaxSize { get { return new Size(0, this.PreferredSize.Height); } }

        Size IXtraResizableControl.MinSize { get { return new Size(0, this.PreferredSize.Height); } }

        #endregion
    }
}

Ссылки по теме:

IXtraResizableControl Interface:
http://documentation.devexpress.com/#WindowsForms/clsDevExpressUtilsControlsIXtraResizableControltopic
FlowLayoutPanel with autosize and layout control:
http://www.devexpress.com/Support/Center/p/Q292593.aspx

Вот собственно и все. Исходный код можете скачать здесь