Показ дописів із міткою programming. Показати всі дописи
Показ дописів із міткою programming. Показати всі дописи

четвер, 29 березня 2012 р.

jQuery: Як клацнути по певному регіоні (jQuery: How to click in certain region)

Уявімо, нам треба клацнути по якомусь елементу, щоб його сховати. Знаходимо цей елемент, додаємо до нього обробку події "click", а також змінюємо CSS стиль відповідним чином.

Якщо ж нам треба клацнути по якомусь регіоні всередині елемента "div"?
Тоді вираховуємо його координати користуючись можливостями jQuery, наприклад, ось так (приклад із сайта на Друпалі):

Drupal.behaviors.samlFirstMsgHide = function(context){
    var scSamlHideFirst = localStorage.getItem("scSamlHideFirst");
    var scSamlFirstVisitMsg = $('div.saml-account-update-message');

    if (scSamlHideFirst){
        scSamlFirstVisitMsg.css("display","none");
    } else {
        scSamlFirstVisitMsg.css("display","block");
        scSamlFirstVisitMsg.click(function(e){
                var minX = 840;
                var minY = 10;
                var maxX = 856;
                var maxY = 24;
                offset = $(this).offset();
                var x = e.pageX - offset.left;
                var y = e.pageY - offset.top;
                if (x < maxX && x > minX && y < maxY && y > minY){
                    $(this).fadeOut();
                    localStorage.setItem("scSamlHideFirst", "true");
                }
        });
    }

};

четвер, 13 січня 2011 р.

Створення wiki в Drupal (Create a wiki with Drupal)

Що потрібно:

  1. Створити новий тип node (напр. “my_wiki_page”).
    Або через інтерфейс Друпал, або через модуль. Тут і надалі буде описуватися створення через написання власного модуля my_wiki.
/**
* Implementation of hook_node_info()
*/
function my_wiki_node_info() {
  return array(
      'my_wiki_page' => array(
        'name' => t('My wiki page'),
        'module' => 'my_wiki',
        'description' => 'My Drupal wiki pages',
        ),
  );
}

/**
 * Implementation of hook_perm()
 */
function my_wiki_perm() {
  return array(
      'create wiki page',
      'edit any wiki page',
      'edit own wiki page',
      'delete any wiki page',
      );
}

/**
 * Implementation of hook_access()
 */
function my_wiki_access($op, $node, $account) {
  // NOTE: For creation operations the $node is a string, not an object

  if ($op == 'create' && $node) {
    // Only users with permission to do so may create this node type.
    if ($node === 'my_wiki_page') {
      return user_access('create wiki page', $account);
    }
  }

  if ($node->type == 'my_wiki_page') {
    // Operations with wiki pages

    // Only users with permission to do so may edit/delete this node type.
    // Users who create a node may edit or delete it later, assuming they have the
    // necessary permissions.
    if ($op == 'update') {
      if (user_access('edit any wiki page', $account)) {
        return TRUE;
      }
      if (user_access('edit own wiki page', $account) && ($account->uid == $node->uid)) {
        return TRUE;
      }
    }

    if ($op == 'delete') {
      if (user_access('delete any wiki page', $account)) {
        return TRUE;
      }
      if (user_access('edit own wiki page', $account) && ($account->uid == $node->uid)) {
        return TRUE;
      }
    }
  }
}

  1. Встановити модулі Wikitools, Diff  та Pathauto. Можна й не встановлювати, якщо правильно вказати залежності модуля, цей модуль встановиться автоматично разом з новим модулем. Досить лише помістити скачаний модуль до директорії "sites/all/modules".
  2. Встановити правильні дозволи.. Всі користувачі повинні мати наступні дозволи:
    "access content",
    "create wiki page",
    "edit own wiki page",
    "view revisions",
    "revert revisions".
    Привілейовані користувачі також можуть додатково мати наступні дозволи:
    "edit any wiki page",
    "delete any wiki page".

  3. Налаштувати шаблони Pathauto. Можна функцією:
    /*
     * Function which creates the "Pathauto" patterns for URLs of content related to wiki pages.
     */
    function _my_wiki_create_pathauto_patterns() {
      $node_type = 'my_wiki_page';
      variable_set('pathauto_node_' . $node_type . '_pattern', 'wiki/[title-raw]');
    }
    

  4. Встановити "My wiki page" як тип сторінки для модуля Wikitools.
    Функція встановлення налаштувань модуля Wikitools:
    /*
     * Function which enables needed settings of the Wikitools module.
     */
    function _my_wiki_wikitools_enable_settings() {
      // Load the "filter_admin_format_form" function and its "_submit".
      module_load_include('inc', 'wikitools', 'wikitools.admin');
    
      // Array of pages that should be used as wiki pages
      $wiki_pages = array(
          'my_wiki_page' => 1,
          );
    
      $wikitools_fields = array();
      $wikitools_fields['values']['wikitools_node_types'] = $wiki_pages;
    
      $wikitools_form = wikitools_admin_settings($wikitools_fields);
      system_settings_form_submit($wikitools_form, $wikitools_fields);
    
      // Print messages
      drupal_set_message();
    }
    
    
    
  5. Виклик останніх функцій слід помістити в hook_enable модуля:
    /**
     * Implementation of hook_enable()
     */
    function my_wiki_enable() {
      // Create needed Pathauto patterns of aliases
      _my_wiki_create_pathauto_patterns();
    
      // Enable needed settings of the Wikitools module.
      _my_wiki_wikitools_enable_settings();
    }
    
    
  6. Встановити правильні поля форми створення сторінки, використавши hook_form хук:
    /**
     * Implementation of hook_form()
     */
    function my_wiki_form(&$node, $form_state) {
      if (!empty($node)) {
        if ($node->type == 'my_wiki_page') {
          // Create modified form for create/edit wiki node.
    
          // Set proper title for wiki page creation
          if (arg(1) === 'add') {
            drupal_set_title(t('Create Wiki Page'));
          }
    
          $type = node_get_types('type', $node);
    
          // Set node parameters
          $node->promote = FALSE;
          $node->revision = 1;
          $node->comment = 0;
    
    
          // Set title
          $form['title'] = array(
              '#type' => 'textfield',
              '#title' => check_plain($type->title_label),
              '#required' => TRUE,
              '#default_value' => $node->title,
              '#weight' => -5
              );
    
          // Set body
          $form['body_filter']['body'] = array(
              '#type' => 'textarea',
              '#title' => check_plain($type->body_label),
              '#default_value' => $node->body,
              '#required' => FALSE
              );
          // Set format
          $form['body_filter']['filter'] = filter_form($node->format);
    
          // Set revisions
          $form['revision_information']['revision']['#default_value'] = $node->revision;
    
          // Disable comments
          if (isset($form['comment_settings']['comment'])) {
            $form['comment_settings']['comment']['#default_value'] = $node->comment;
          }
    
          // Node options for administrators
          $form['options'] = array(
              '#type' => 'fieldset',
              '#access' => user_access('administer nodes'),
              '#title' => t('Publishing options'),
              '#collapsible' => TRUE,
              '#collapsed' => TRUE,
              '#weight' => 25,
              );
    
          $form['options']['promote'] = array(
              '#type' => 'checkbox',
              '#title' => t('Promoted to front page'),
              '#default_value' => $node->promote,
              );
    
          return $form;
        }
      }
    }
    
    

  7. Встановити CKEditor як редактор для сторінок або використовувати якийсь із вікі-фільтрів, наприклад: flexifilter або pearwiki filter.

Тепер (після встановлення цього модуля) за шляхом "/wiki" Вашого сайту Вам буде запропоновано створити головну сторінку ("Main Page"). Так само, якщо ввести шлях типу "http://<Ваш сайт>/wiki/test", Вам буде запропоновано створити дану сторінку. Модуль Diff надасть можливість порівнювати зміни між ревізіями файла.

Дивіться також: http://cwgordon.com/how-to-create-a-wiki-with-drupal.

PS. Вміст .info файла  для модуля:

; $Id$
name = "My wiki"
description = "Module which provides wiki pages"
package = "My modules"
version = 1.0
core = 6.x

dependencies[] = diff
dependencies[] = pathauto
dependencies[] = wikitools

пʼятниця, 29 жовтня 2010 р.

Встановлення ваги для модуля Drupal (Setting weight for the module)

Встановити вагу (приоритет) для модуля можна встановити додаванням наступного рядка в "hook_install" хук:

db_query("UPDATE {system} SET weight = 100000 WHERE name = 'ics_module'");


Хуки даного модуля виконуватимуться після хуків модулів з меншими вагами.

пʼятниця, 22 жовтня 2010 р.

ID змінених рядків в PostgreSQL

Нещодавно виникло питання як узнати ID останнього вставленого рядка в таблиці для PostgreSQL. В Perl'і це робиться через dbh->last_insert_id.

Виявилося, що можливо узнати це і безпосередньо через SQL запит, слід лише використати службове слово RETURNING.

Для таблиці, створеної наступною командою:
CREATE TABLE test_table
(
  id serial NOT NULL,
  "name" character varying NOT NULL,
  PRIMARY KEY (id)
);


Операція INSERT з поверненням ID виглядатиме так:
INSERT INTO test_table (name)
    VALUES ('test name')
    RETURNING id; 

Якщо у нас є більше одного рядка з name = 'test name', наступна операція UPDATE поверне список змінених ID:
UPDATE test_table
SET
  name = 'TEST name'
WHERE
  name = 'test name'
RETURNING id;

четвер, 13 травня 2010 р.

Універсальний тип даних для вказівника (C/C++ pointer)

Вирішував нещодавно цікаву задачу: як правильно здійснити приведення типу для вказівника типу (void *)? Якщо на 32-бітних системах розмір вказівника рівний розміру типу даних int, то в 64-бітних системах усе залежить від реалізації. Наприклад, тип int може бути як 32-бітним (Microsoft Win64, більшість UNIX-подібних систем), так і 64-бітним (якщо система використовує модель даних ILP64 або SILP64). Аналогічна ситуація і з типом long: він 64-бітний на більшості систем, проте є системи, де його розмірність рівна 32 біт. Детальніше про це можна прочитати тут:
http://en.wikipedia.org/wiki/64-bit#Specific_C-language_data_models.

Отже, задача звелася до того, що слід мати універсальний тип даних, розмірність якого завжди відповідає розмірності вказівника. Як виявилося, в UNIX-подібних системах існують спеціальні типи даних, спроектовані для операцій з вказівниками, такі як ptrdiff_t, intptr_t, uintptr_t.
Тип ptrdiff_t призначений зберігання результатів віднімання вказівників і є знаковим.
Тип intptr_t є його синонімом.
Тип uintptr_t є беззнаковим цілочисельним типом і здатен безпечно зберігати у собі вказівник незалежно від розрядності платформи.

Отже, для моєї задачі потрібен був тип uintptr_t. Слід було лише виявити, для якої платформи який заголовний файл (header) слід включити, щоб використати цей тип.
Ось список заголовних файлів відповідно для системи:
GNU/Linux - stdint.h;
Solaris - inttypes.h;
AIX - inttypes.h;
IRIX - додадковий заголовний файл не потрібен;
HP-UX - sys/wsio.h.

Відповідно, універсальний код для включення типу uintptr_t:

#if defined(__hpux)
#include <sys/wsio.h>
#else
# if defined(__sun) || defined(_AIX)
#include <inttypes.h>
# else
# ifndef __sgi
#include <stdint.h>
# endif
# endif
#endif

середа, 14 квітня 2010 р.

Проблеми з повторними генераціями сигналу finished для QNetworkReply

Вчора зіткнувся з досить неочевидною проблемою при тестуванні QT-аплікації. Після відсилання мережевого запиту обробка відповіді відбувається у функції, прив'язаній до сигналу finished.
Робота з мережевими запитами в QT описана ось тут Creating_an_HTTP_network_request_in_Qt

Ось, власне, прив'язка у моєму випадку:
connect(_networkManager, SIGNAL(finished(QNetworkReply*)), this,
    SLOT(replyFinished(QNetworkReply*)));

Виявилося, що цей сигнал генерується декілька разів: QNetworkReply завершив роботу, перед знищенням об'єкта QNetworkReply або під час його закриття функціями close() чи abort(). При цьому лише у першому випадку з нього можна щось прочитати, у решті - ні, що призводить до помилок при парсінгу даних і зупинки обробки наступних запитів (у моєму випадку відбувається перевірка статусу попереднього запиту перед відправкою наступного).

Правильним рішенням було відключити всі слоти від сигналів QNetworkReply, щоб не отримувати їх після завершення обробки даних. Ось як це реалізовано:
void MyClass::replyFinished(QNetworkReply* reply) {
    // --------------------------------------
    // Тут насправді міститься обробка даних
    // --------------------------------------

    // Close and clean up.
    m_networkManager->disconnect();
    reply->close();
    reply->deleteLater();
}

неділя, 20 грудня 2009 р.

Деякі проблеми лінкування динамічних бібліотек на AIX

На жаль, не зміг опублікувати це по свіжих слідах, тому спробую зробити це по пам'яті і старих записках.

Якось я майже два тижні витратив на вирішення проблеми, пов'язаної з лінкуванням динамічних бібліотек на IBM AIX 5.1.

Проблема полягала в тому, що створена динамічна бібліотека викликала падіння аплікації при спробі використати будь-яку функцію з бібліотеки, що означало, що бібліотека зібрана не так, як слід. Дослідження показало, що проблема була в тому, що на AIX слід явно експортувати всі необхідні символи, причому як від бібліотеки до програми, так і в зворотньому напрямку.

Граючись із різними опціями та читаючи документацію, я виявив, що зараз (починаючи з IBM AIX 5.1) замість цілого ряду опцій для включення створення динамічної бібліотеки, дозволу run-time лінкування, та ін., можна використати всього лише опцію -G, яка вкаже лінкеру на необхідність створення shared object з можливістю run-time лінкування. Також слід вказати опцію -bE:exportlist де "exportlist" -- назва файлу зі списком символів (класів та функцій) з бібліотеки, які мають бути викликані з головної аплікації.
Якщо ми використовуємо run-time лінкування, головна аплікація має бути зібрана з опцією -brtl. Для самої аплікації також слід вказати -bE:exportlist_app, де "exportlist_app" -- назва файлу з символами, які експортуються з аплікації, щоб бути видимими у бібліотеці.

У моєму випадку "exportlist" бібліотеки містив її функції та клас "theApplication" з іншої бібліотеки. Файл "exportlist_app" для аплікації містив лише клас "theApplication", інакше у бібліотеці символ "theApplication" з аплікації був недоступний. В результаті це символ у програмі був оголошений двічі -- один раз явно проініціалізований у головній аплікації, а інший -- із конструктором по замовчуванню в моїй бібліотеці, що приводило до падіння аплікації (хоча явного виклику конструктора чи створення об'єкта класу і не було, через недоступність об'єкта класу з аплікації, лінкер створював новий об'єкт у бібліотеці).

Узагальнюючи, ось процес створення динамічної бібліотеки на IBM AIX:
  1. Скомпілювати кожен вихідний файл в об'єктний файл, без лінкування. Наприклад:
    xlc -c foo.c -o foo.o
  2. Створити експортний файл, у якому перераховуються глобальні символи, які мають бути експортовані. Автоматичний спосіб генерує багато зайвого, тому я створював вручну, щось типу такого:
    function_one
    function_two
    ....
    class_one
    ....
  3. Використати опцію -G для створення динамічної бібліотеки зі згенерованих об'єктних файлів, щоб мати символи, які лінкуються до аплікації під час завантаження, і опцію лінкера -bE для вказання імені експортного файлу. (Також можна використати опцію -qmkshrobj для вказання пріоритету для C++ shared object; див. Initializing static objects in libraries (C++).) Наприклад:
    xlc -G -o libfoo.so foo1.o foo2.o -bE:exportlist
  4. Злінкувати бібліотеку з головною аплікацією, якщо бібліотека використовує run-time лінкування, додати опцію -brtl (а також -bE за потребою):
    xlc  -bE:main.exp -brtl -o myprogram main.c -Ldirectory -lfoo