[Zope-CVS] CVS: Products/CompositePage/common - bottom.pt:1.1 edit.js:1.1 editstyles.css:1.1 header.pt:1.1 pdlib.js:1.1 pdstyles.css:1.1

Shane Hathaway shane at zope.com
Fri Sep 26 17:21:07 EDT 2003


Update of /cvs-repository/Products/CompositePage/common
In directory cvs.zope.org:/tmp/cvs-serv25375/common

Added Files:
	bottom.pt edit.js editstyles.css header.pt pdlib.js 
	pdstyles.css 
Log Message:
Added the CompositePage product.

CompositePage is like the PageDesign product, but simplified, and now based
on PDLib, a Javascript drag and drop / context menu library.



=== Added File Products/CompositePage/common/bottom.pt ===
<!-- common/bottom.pt -->
<div id="drag-feedback-box"></div>

<form action="moveAndDelete" name="modify_composites" method="POST"
  tal:attributes="action
  string:${options/tool/absolute_url}/moveAndDelete">
<input type="hidden" name="move_source_paths" value="" />
<input type="hidden" name="move_target_path" value="" />
<input type="hidden" name="move_target_index" value="" />
<input type="hidden" name="delete_source_paths" value="" />
</form>

<script type="text/javascript"><!--
pd_setupPage();
// --></script>


=== Added File Products/CompositePage/common/edit.js ===

// Composite editing scripts (based on PDLib)

function composite_move(selected_items, target_node) {
  var f, i, path, sources, s;
  f = document.forms.modify_composites;
  i = target_node.getAttribute("target_index");
  path = target_node.getAttribute("target_path");
  f.elements.move_target_index.value = i;
  f.elements.move_target_path.value = path;

  sources = "";
  for (i = 0; i < selected_items.length; i++) {
    s = selected_items[i].getAttribute("source_path");
    if (s) {
      if (sources)
        sources = sources + ":" + s;
      else
        sources = s;
    }
  }
  f.elements.move_source_paths.value = sources;
  f.submit();
}

function composite_checkmove(selected_items, target_node) {
  var target_path, source_path, i;
  target_path = target_node.getAttribute("target_path");
  for (i = 0; i < selected_items.length; i++) {
    source_path = selected_items[i].getAttribute("source_path");
    if (source_path) {
      source_path = source_path + "/";  // Terminate on full names
      // window.status = "From " + source_path + " to " + dest_path;
      if (target_path.slice(0, source_path.length) == source_path) {
        // Don't allow a parent to become its own child.
        return false;
      }
    }
  }
  return true;
}

function composite_delete(selected_items) {
  var f, i, s, sources;
  if (!selected_items)
    return;
  f = document.forms.modify_composites;
  sources = "";
  for (i = 0; i < selected_items.length; i++) {
    s = selected_items[i].getAttribute("source_path");
    if (s) {
      if (sources)
        sources = sources + ":" + s;
      else
        sources = s;
    }
  }
  f.elements.delete_source_paths.value = sources;
  f.submit();
}

function composite_highlightTarget(node, state) {
  if (state == 0)
    node.style.background = "inherit";
  else if (state == 1)
    node.style.background = "black";
  else if (state == 2)
    node.style.background = "green";
}


function setUpSlotTarget(node) {
  pd_setupDropTarget(node, 0, composite_highlightTarget);
  pd_setupContextMenu(node, 'slot-target-context-menu', null, true);
}

pd_node_setup['slot_target'] = setUpSlotTarget;


function setUpSlotElement(node) {
  pd_setupDragUI(node, composite_move, composite_checkmove);
  pd_setupContextMenu(node, 'slot-element-context-menu', null, true);
}

pd_node_setup['slot_element'] = setUpSlotElement;



=== Added File Products/CompositePage/common/editstyles.css ===
/* Composite editing styles */

div#drag-feedback-box {
  border: 1px dotted black;
  position: absolute;
  display: none;
  z-index: 1000;
}

.slot_target {
  padding: 2px;
  border-top: 1px dashed #0000ff;
  border-left: 1px dashed #0000ff;
  margin: 1px;
}

.slot_element {
  background: #dddddd;
  border: 1px inset #dddddd;
}


=== Added File Products/CompositePage/common/header.pt ===
<!-- common/header.pt -->
<tal:block tal:define="url options/transformer/absolute_url">
<link rel="stylesheet" type="text/css"
  tal:attributes="href string:${url}/pdstyles_css" />
<link rel="stylesheet" type="text/css"
  tal:attributes="href string:${url}/editstyles_css" />
<script type="text/javascript" 
  tal:attributes="src string:${url}/pdlib_js"></script>
<script type="text/javascript" 
  tal:attributes="src string:${url}/edit_js"></script>
</tal:block>


=== Added File Products/CompositePage/common/pdlib.js ===
// Copyright (c) 2002 Zope Corporation and Contributors.
// All Rights Reserved.
//
// This software is subject to the provisions of the Zope Public License,
// Version 2.0 (ZPL).  A copy of the ZPL should accompany this distribution.
// THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
// WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
// FOR A PARTICULAR PURPOSE.

// Page design Javascript library

// A library for manipulating objects on a page with object selection,
// context menus, and drag and drop.  Mostly DOM 2 oriented, with bits
// for IE compatibility.
// $Id: pdlib.js,v 1.1 2003/09/26 21:21:05 shane Exp $

// The following variables and functions are documented for use by
// scripts that use this library:
//
//   pd_node_setup
//   pd_selected_item
//   pd_selected_items
//   pd_library_version
//
//   pd_stopEvent()
//   pd_findEventTarget()
//   pd_hideContextMenu()
//   pd_isSelected()
//   pd_select()
//   pd_deselect()
//   pd_clearSelection()
//   pd_setupContextMenu()     -- adds a context menu to an element
//   pd_setupDragUI()          -- adds drag/drop functionality to an element
//   pd_setupDropTarget()      -- turns an element into a drop target
//   pd_setupContextMenuDefinition() -- turns an element into a context menu
//   pd_setupPage()            -- Page initialization (call at bottom of page)
//
// See the documentation for descriptions.
// All other names are subject to change in future revisions.

var pd_library_version = '0.2';  // The pdlib version.  Avoid using this!
var pd_open_context_menu = null; // The context menu node being displayed
var pd_drag_event = null;        // A pd_DragEvent object while dragging
var pd_selected_items = null;    // List of selected items
var pd_selected_item = null;     // Non-null when exactly one item is selected
var pd_drag_select_mode = null;  // -1 or 1 in drag-select mode, otherwise null
var pd_node_setup = {};          // Object containing node setup functions
var pd_max_contextmenu_width = 250; // Threshold for faulty browsers
var pd_invisible_targets = [];   // A list of normally invisible drop targets


function pd_hasAncestor(node, ancestor) {
  var p = node;
  while (p) {
    if (p == ancestor)
      return true;
    p = p.parentNode;
  }
  return false;
}

function pd_stopEvent(e) {
  if (!e)
    e = event;
  if (e.stopPropagation)
    e.stopPropagation();
  else
    e.cancelBubble = true;
  return false;
}

function pd_findEventTarget(e, className, stop_className) {
  // Search for a node of the given class among the ancestors of the
  // target of an event, stopping if stop_className is encountered.
  // Note that elements with multiple classes are not supported by
  // this function.
  var node = e.target || e.srcElement;
  while (node) {
    if (node.className == className)
      return node;
    if (stop_className && node.className == stop_className)
      return null;
    node = node.parentNode;
  }
  // Not found.
  return null;
}

function pd_highlight(node, enabled) {
  node.style.color = enabled ? "HighlightText" : "";
  node.style.backgroundColor = enabled ? "Highlight" : "";
}

function pd_defaultHighlightTarget(node, state) {
  if (state == 0)
    node.style.border = "2px solid transparent";
  else if (state == 1)
    node.style.border = "2px dotted red";
  else if (state == 2)
    node.style.border = "2px solid green";
}

//
// Context menu functions
//

function pd_showContextMenu(menunode, e) {
  if (!e)
    e = event;
  // Close any open menu
  pd_hideContextMenu();
  var page_w = window.innerWidth || document.body.clientWidth;
  var page_h = window.innerHeight || document.body.clientHeight;
  var page_x = window.pageXOffset || document.body.scrollLeft;
  var page_y = window.pageYOffset || document.body.scrollTop;

  if (menunode.offsetWidth >= pd_max_contextmenu_width) {
    // It's likely that the browser ignored "display: table"
    // and used the full width of the page.  Use a workaround.
    menunode.style.width = '' + (pd_max_contextmenu_width) + 'px';
  }

  // Choose a location for the menu based on where the user clicked
  if (page_w - e.clientX < menunode.offsetWidth) {
    // Close to the right edge
    menunode.style.left = '' + (
      page_x + e.clientX - menunode.offsetWidth - 1) + 'px';
  }
  else {
    menunode.style.left = '' + (page_x + e.clientX + 1) + 'px';
  }
  if (page_h - e.clientY < menunode.offsetHeight) {
    // Close to the bottom
    menunode.style.top = '' + (
      page_y + e.clientY - menunode.offsetHeight - 1) + 'px';
  }
  else {
    menunode.style.top = '' + (page_y + e.clientY + 1) + 'px';
  }

  pd_open_context_menu = menunode;
  menunode.style.visibility = "visible";
  return false;
}

function pd_hideContextMenu() {
  if (pd_open_context_menu) {
    pd_open_context_menu.style.visibility = "hidden";
    pd_open_context_menu = null;
  }
}

function pd_getContextMenuItem(e) {
  return pd_findEventTarget(e, "context-menu-item", "context-menu");
}

function pd_highlightContextMenuItem(e) {
  if (!e)
    e = event;
  var node = pd_getContextMenuItem(e);
  if (node)
    pd_highlight(node, true);
}

function pd_unhighlightContextMenuItem(e) {
  if (!e)
    e = event;
  var node = pd_getContextMenuItem(e);
  if (node)
    pd_highlight(node, false);
}

function pd_filterContextMenuItems(node) {
  // Execute filter scripts and set the "display" style property
  var i, f, enabled;
  if (node.getAttribute) {
    f = node.getAttribute("filter");
    if (f) {
      enabled = eval(f);
      if (enabled)
        node.style.display = "";
      else
        node.style.display = "none";
    }
  }
  for (i = 0; i < node.childNodes.length; i++)
    pd_filterContextMenuItems(node.childNodes[i]);
}

//
// Drag functions
//

function pd_DragEvent(e, move_func, checkmove_func) {
  this.target = null;
  this.move_func = move_func;
  this.checkmove_func = checkmove_func;
  this.highlight_func = null;
  this.start_x = e.pageX ? e.pageX : e.clientX + document.body.scrollLeft;
  this.start_y = e.pageY ? e.pageY : e.clientY + document.body.scrollTop;
  this.feedback_node = document.getElementById("drag-feedback-box");
  this.began_moving = false;
  this.revealed = [];
}

function pd_allowDrop(target) {
  if (!pd_drag_event)
    return false;
  var i;
  for (i = 0; i < pd_selected_items.length; i++) {
    if (pd_hasAncestor(target, pd_selected_items[i])) {
      // Don't let the user drag an element inside itself.
      return false;
    }
  }
  if (pd_drag_event.checkmove_func) {
    if (!pd_drag_event.checkmove_func(pd_selected_items, target))
      return false;
  }
  return true;
}

function pd_unhighlightTarget() {
  if (pd_drag_event && pd_drag_event.target) {
    pd_drag_event.highlight_func(pd_drag_event.target, 0);
    pd_drag_event.target = null;
  }
}

function pd_setHighlightedTarget(target, highlight_func) {
  if (pd_allowDrop(target)) {
    pd_unhighlightTarget();
    if (!highlight_func)
      highlight_func = pd_defaultHighlightTarget;
    highlight_func(target, 1);
    pd_drag_event.target = target;
    pd_drag_event.highlight_func = highlight_func;
  }
}

function pd_firstDrag(x, y) {
  if (!pd_drag_event)
    return;
  var i, target;
  var feedback_node_style = pd_drag_event.feedback_node.style;
  var item = pd_selected_items[0];  // TODO: expand box to include all items

  pd_drag_event.began_moving = true;
  feedback_node_style.left = '' + (x + 5) + 'px';
  feedback_node_style.top = '' + (y + 5) + 'px';
  feedback_node_style.width = '' + (item.offsetWidth - 2) + 'px';
  feedback_node_style.height = '' + (item.offsetHeight - 2) + 'px';
  feedback_node_style.display = "block";

  // Show some of the normally invisible targets.
  for (i = 0; i < pd_invisible_targets.length; i++) {
    target = pd_invisible_targets[i];
    if (pd_allowDrop(target)) {
      if (pd_drag_event.revealed.push)
        pd_drag_event.revealed.push(target);
      else
        pd_drag_event.revealed = pd_drag_event.revealed.concat([target]);
      target.style.visibility = "visible";
    }
  }
}

function pd_dragging(e) {
  if (!pd_drag_event)
    return;
  if (!e)
    e = event;
  var x = e.pageX ? e.pageX : e.clientX + document.body.scrollLeft;
  var y = e.pageY ? e.pageY : e.clientY + document.body.scrollTop;

  if (!pd_drag_event.began_moving) {
    if (Math.abs(x - pd_drag_event.start_x) <= 3 &&
        Math.abs(y - pd_drag_event.start_y) <= 3) {
      // Didn't move far enough yet.
      return;
    }
    pd_firstDrag(x, y);
  }
  pd_drag_event.feedback_node.style.left = '' + (x + 5) + 'px';
  pd_drag_event.feedback_node.style.top = '' + (y + 5) + 'px';
}

function pd_finishDrag() {
  var i;
  for (i = 0; i < pd_drag_event.revealed.length; i++)
    pd_drag_event.revealed[i].style.visibility = '';

  document.onmousemove = null;
  document.onmouseup = null;
  document.onselectstart = null;
  pd_drag_event.feedback_node.style.display = "none";
  var ev = pd_drag_event;
  pd_drag_event = null;

  if (ev.target) {
    if (ev.highlight_func)
      ev.highlight_func(ev.target, 2);
    if (ev.move_func)
      ev.move_func(pd_selected_items, ev.target);
  }
}

function pd_startDrag(e, move_func, checkmove_func) {
  if (pd_drag_event) {
    // Already dragging
    return;
  }
  if (!e)
    e = event;
  pd_drag_event = new pd_DragEvent(e, move_func, checkmove_func);
  document.onmousemove = pd_dragging;
  document.onmouseup = pd_finishDrag;
  document.onselectstart = pd_stopEvent;  // IE: Don't start a selection.
  if (e.preventDefault)
    e.preventDefault();  // NS 6: Don't start a selection.
}

//
// Selection management functions
//

function pd_isSelected(node) {
  if (pd_selected_items) {
    for (var i = 0; i < pd_selected_items.length; i++) {
      if (node == pd_selected_items[i]) {
        return true;
      }
    }
  }
  return false;
}

function pd_changedSelection() {
  if (pd_selected_items && pd_selected_items.length == 1)
    pd_selected_item = pd_selected_items[0];
  else
    pd_selected_item = null;
}

function pd_deselect(node) {
  var i, n;
  if (pd_selected_items) {
    var newsel = [];
    // There must be a better way.  This could be slow.
    for (i = 0; i < pd_selected_items.length; i++) {
      n = pd_selected_items[i];
      if (n != node) {
        if (newsel.push)
          newsel.push(n)
        else
          newsel = newsel.concat([n]);
      }
    }
    pd_selected_items = newsel;
    pd_changedSelection();
  }
  pd_highlight(node, false);
}

function pd_select(node) {
  if (!pd_isSelected(node)) {
    if (!pd_selected_items)
      pd_selected_items = [node];
    else if (pd_selected_items.push)
      pd_selected_items.push(node);
    else
      pd_selected_items = pd_selected_items.concat([node]);
    pd_changedSelection();
  }
  pd_highlight(node, true);
}

function pd_clearSelection() {
  var i, node, n;
  if (pd_selected_items) {
    for (i = 0; i < pd_selected_items.length; i++)
      pd_highlight(pd_selected_items[i], false);
  }
  pd_selected_items = [];
  pd_changedSelection();
}

function pd_dragSelecting(node) {
  if (pd_drag_select_mode == 1)
    pd_select(node);
  else if (pd_drag_select_mode == -1)
    pd_deselect(node);
}

function pd_endDragSelect() {
  pd_drag_select_mode = null;
  document.onmouseup = null;
}

function pd_startDragSelect(v) {
  document.onmouseup = pd_endDragSelect;
  pd_drag_select_mode = v;
}


//
// On-page object management functions
//

function pd_itemOnMousedown(mo, e, move_func, checkmove_func, box) {
  if (!e)
    e = event;
  if (e.button == 0 || e.button == 1) {
    pd_hideContextMenu();
    if (!box)
      box = mo;
    if (e.shiftKey) {
      // Toggle the selected state of this item and start drag select.
      if (pd_isSelected(box)) {
        pd_deselect(box);
        pd_startDragSelect(-1);
      }
      else {
        pd_select(box);
        pd_startDragSelect(1);
      }
    }
    else if (e.ctrlKey) {
      if (pd_isSelected(box))
        pd_deselect(box);
      else
        pd_select(box);
    }
    else {
      if (!pd_isSelected(box)) {
        pd_clearSelection();
        pd_select(box);
      }
      pd_startDrag(e, move_func, checkmove_func);
    }
  }
  return pd_stopEvent(e);
}

function pd_itemOnMouseover(mo, e, box) {
  if (pd_drag_select_mode) {
    pd_dragSelecting(box || mo);
    return pd_stopEvent(e);
  }
}

function pd_itemOnContextMenu(mo, e, contextMenuId, box) {
  if (!e)
    e = event;
  if (!box)
    box = mo;
  if (!pd_isSelected(box)) {
    pd_clearSelection();
    pd_select(box);
  }
  var menu = document.getElementById(contextMenuId);
  if (menu) {
    pd_filterContextMenuItems(menu);
    pd_showContextMenu(menu, e);
    return pd_stopEvent(e);
  }
}

function pd_setupDragUI(mo, move_func, checkmove_func, box) {
  // Adds selection and drag and drop functionality to an element
  function call_onmousedown(e) {
    return pd_itemOnMousedown(mo, e, move_func, checkmove_func, box);
  }
  function call_onmouseover(e) {
    return pd_itemOnMouseover(mo, e, box);
  }
  mo.onmousedown = call_onmousedown;
  mo.onmouseover = call_onmouseover;
  mo.onselectstart = pd_stopEvent;  // IE: Don't start a selection.
}

function pd_setupContextMenu(mo, contextMenuId, box, onclick) {
  // Adds context menu functionality to an element
  function oncontextmenu(e) {
    return pd_itemOnContextMenu(mo, e, contextMenuId, box);
  }
  mo.oncontextmenu = oncontextmenu;
  if (onclick)
    mo.onclick = oncontextmenu;
}

function pd_documentOnMouseDown() {
  pd_hideContextMenu();
  pd_clearSelection();
}

function pd_setupNodeAndDescendants(node) {
  var i, f, names;
  if (node.className) {
    names = node.className.split(" ");
    for (i = 0; i < names.length; i++) {
      if (names[i]) {
        f = pd_node_setup[names[i]];
        if (f)
          f(node);
      }
    }
  }
  for (i = 0; i < node.childNodes.length; i++) {
    pd_setupNodeAndDescendants(node.childNodes[i]);
  }
}

function pd_setupPage(node) {
  if (!node)
    node = document;
  if (!document.onmousedown)
    document.onmousedown = pd_documentOnMouseDown;
  pd_setupNodeAndDescendants(node);
}

function pd_setupDropTarget(node, selectable, highlight_func) {
  function call_highlight() {
    return pd_setHighlightedTarget(node, highlight_func);
  }
  node.onmouseover = call_highlight;
  node.onmouseout = pd_unhighlightTarget;
  if (!selectable)
    node.onmousedown = pd_stopEvent; // Prevent accidental selection
}

function pd_setupContextMenuDefinition(node) {
  node.onmouseover = pd_highlightContextMenuItem;
  node.onmouseout = pd_unhighlightContextMenuItem;
  node.onmousedown = pd_stopEvent;
  node.onmouseup = pd_hideContextMenu;
}

pd_node_setup['drop-target'] = pd_setupDropTarget;
pd_node_setup['context-menu'] = pd_setupContextMenuDefinition;


=== Added File Products/CompositePage/common/pdstyles.css ===
/* Manageable Object Styles (CSS 2) */

.context-menu {
  position: absolute;
  border: 1px outset Menu;
  background-color: Menu;
  color: MenuText;
  cursor: default;
  z-index: 1000;
  visibility: hidden;
  display: table;
}

.context-menu-item {
  padding-left: 10px;
  padding-right: 10px;
  padding-top: 2px;
  padding-bottom: 2px;
}

.separator {
  border-top: 1px inset Menu;
  border-bottom: 1px inset Menu;
}




More information about the Zope-CVS mailing list