From duncan at codespeak.net Fri Sep 1 11:52:46 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Fri, 1 Sep 2006 11:52:46 +0200 (CEST) Subject: [kupu-checkins] r31911 - kupu/trunk/kupu/common Message-ID: <20060901095246.50DF710060@code0.codespeak.net> Author: duncan Date: Fri Sep 1 11:52:45 2006 New Revision: 31911 Modified: kupu/trunk/kupu/common/kupueditor.js Log: Workround for IE rejecting bad html. Needs a proper solution though. Modified: kupu/trunk/kupu/common/kupueditor.js ============================================================================== --- kupu/trunk/kupu/common/kupueditor.js (original) +++ kupu/trunk/kupu/common/kupueditor.js Fri Sep 1 11:52:45 2006 @@ -651,6 +651,7 @@ return '<'+close+tag+'>'; }); }; + text = text.replace(/

()<\/p>/,'$1'); bodies[bodies.length-1].innerHTML = text; }; From duncan at codespeak.net Fri Sep 1 12:07:11 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Fri, 1 Sep 2006 12:07:11 +0200 (CEST) Subject: [kupu-checkins] r31913 - in kupu/trunk/kupu: common doc plone Message-ID: <20060901100711.A6DDD10060@code0.codespeak.net> Author: duncan Date: Fri Sep 1 12:07:10 2006 New Revision: 31913 Modified: kupu/trunk/kupu/common/kupuhelpers.js kupu/trunk/kupu/common/sarissa_ieemu_xpath.js kupu/trunk/kupu/doc/CHANGES.txt kupu/trunk/kupu/plone/body.kupu kupu/trunk/kupu/plone/plonelibrarytool.py Log: Merged Plone 2.1 fixes from revisions 30984 to 30993. Modified: kupu/trunk/kupu/common/kupuhelpers.js ============================================================================== --- kupu/trunk/kupu/common/kupuhelpers.js (original) +++ kupu/trunk/kupu/common/kupuhelpers.js Fri Sep 1 12:07:10 2006 @@ -122,9 +122,9 @@ }; wrappedmethod.args = args; try { - if (_SARISSA_IS_MOZ) { + if (element.addEventListener) { element.addEventListener(event, wrappedmethod.execute, false); - } else if (_SARISSA_IS_IE) { + } else if (element.attachEvent) { element.attachEvent("on" + event, wrappedmethod.execute); } else { throw _("Unsupported browser!"); @@ -141,9 +141,9 @@ function removeEventHandler(element, event, method) { /* method to remove an event handler for both IE and Mozilla */ - if (_SARISSA_IS_MOZ) { - window.removeEventListener(event, method, false); - } else if (_SARISSA_IS_IE) { + if (element.removeEventListener) { + element.removeEventListener(event, method, false); + } else if (element.detachEvent) { element.detachEvent("on" + event, method); } else { throw _("Unsupported browser!"); @@ -253,6 +253,9 @@ }; }; var name = child.nodeName.toLowerCase(); + if (child.attributes[0] && /^_/.test(child.attributes[0])) { + name += child.attributes[0].toLowerCase(); // Fix for Opera + } if (dict[name] != undefined) { if (!dict[name].push) { dict[name] = new Array(dict[name], value); Modified: kupu/trunk/kupu/common/sarissa_ieemu_xpath.js ============================================================================== --- kupu/trunk/kupu/common/sarissa_ieemu_xpath.js (original) +++ kupu/trunk/kupu/common/sarissa_ieemu_xpath.js Fri Sep 1 12:07:10 2006 @@ -24,6 +24,7 @@ * */ if(_SARISSA_HAS_DOM_FEATURE && document.implementation.hasFeature("XPath", "3.0")){ + var xmldoc = window.XMLDocument || window.Document; /** *

SarissaNodeList behaves as a NodeList but is only used as a result to selectNodes, * so it also has some properties IEs proprietery object features.

@@ -57,7 +58,7 @@ */ SarissaNodeList.prototype.expr = ""; /** dummy, used to accept IE's stuff without throwing errors */ - XMLDocument.prototype.setProperty = function(x,y){}; + xmldoc.prototype.setProperty = function(x,y){}; /** *

Programmatically control namespace URI/prefix mappings for XPath * queries.

@@ -104,9 +105,9 @@ * @private Flag to control whether a custom namespace resolver should * be used, set to true by Sarissa.setXpathNamespaces */ - XMLDocument.prototype._sarissa_useCustomResolver = false; + xmldoc.prototype._sarissa_useCustomResolver = false; /** @private */ - XMLDocument.prototype._sarissa_xpathNamespaces = new Array(); + xmldoc.prototype._sarissa_xpathNamespaces = new Array(); /** *

Extends the XMLDocument to emulate IE's selectNodes.

* @argument sExpr the XPath expression to use @@ -115,7 +116,7 @@ * @returns the result of the XPath search as a SarissaNodeList * @throws An error if no namespace URI is found for the given prefix. */ - XMLDocument.prototype.selectNodes = function(sExpr, contextNode){ + xmldoc.prototype.selectNodes = function(sExpr, contextNode){ var nsDoc = this; var nsresolver = this._sarissa_useCustomResolver ? function(prefix){ @@ -156,7 +157,7 @@ * method when called on Elements * @returns the result of the XPath search as an (Sarissa)NodeList */ - XMLDocument.prototype.selectSingleNode = function(sExpr, contextNode){ + xmldoc.prototype.selectSingleNode = function(sExpr, contextNode){ var ctx = contextNode?contextNode:null; sExpr = "("+sExpr+")[1]"; var nodeList = this.selectNodes(sExpr, ctx); @@ -180,4 +181,5 @@ throw "Method selectNodes is only supported by XML Elements"; }; Sarissa.IS_ENABLED_SELECT_NODES = true; + xmldoc = undefined; }; Modified: kupu/trunk/kupu/doc/CHANGES.txt ============================================================================== --- kupu/trunk/kupu/doc/CHANGES.txt (original) +++ kupu/trunk/kupu/doc/CHANGES.txt Fri Sep 1 12:07:10 2006 @@ -2,7 +2,7 @@ Kupu changes ============ -- 1.4/SVN unreleased +- 1.4 Beta 1 - Fixed some problems with handling of multi-valued form fields in the ExternalSource tool code for Silva. @@ -34,6 +34,14 @@ Word the HTML can be cleaned up simply by toggling source view on/off. +- 1.3.8 + + - HTML view now does filtering by default in Plone (can be turned + off in the configlet). This also means that after pasting from e.g. + Word the HTML can be cleaned up simply by toggling source view + on/off. + + - 1.3.6 - Plone Modified: kupu/trunk/kupu/plone/body.kupu ============================================================================== --- kupu/trunk/kupu/plone/body.kupu (original) +++ kupu/trunk/kupu/plone/body.kupu Fri Sep 1 12:07:10 2006 @@ -14,7 +14,7 @@ tal:define="base python:here.kupu_library_tool.getBaseUrl(here, True); base kupu_base_override|base;" tal:attributes="src string:${base}/emptypage; - tabindex python:tabindex is not None and tabindex + 1 or None;" + tabindex tabindex/next|nothing;" > Author: duncan Date: Fri Sep 1 17:01:13 2006 New Revision: 31935 Added: kupu/tag/kupu-1.4b1/ - copied from r31934, kupu/trunk/kupu/ Log: Tag 1.4 beta 1 From duncan at codespeak.net Fri Sep 1 17:02:02 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Fri, 1 Sep 2006 17:02:02 +0200 (CEST) Subject: [kupu-checkins] r31936 - in kupu/tag/kupu-1.4b1: . default Message-ID: <20060901150202.6BCE71006C@code0.codespeak.net> Author: duncan Date: Fri Sep 1 17:02:01 2006 New Revision: 31936 Modified: kupu/tag/kupu-1.4b1/default/toolbar.kupu kupu/tag/kupu-1.4b1/version.txt Log: Fix version numbers Modified: kupu/tag/kupu-1.4b1/default/toolbar.kupu ============================================================================== --- kupu/tag/kupu-1.4b1/default/toolbar.kupu (original) +++ kupu/tag/kupu-1.4b1/default/toolbar.kupu Fri Sep 1 17:02:01 2006 @@ -52,7 +52,7 @@ Modified: kupu/tag/kupu-1.4b1/version.txt ============================================================================== --- kupu/tag/kupu-1.4b1/version.txt (original) +++ kupu/tag/kupu-1.4b1/version.txt Fri Sep 1 17:02:01 2006 @@ -1 +1 @@ -kupu 1.4 +kupu 1.4b1 From duncan at codespeak.net Mon Sep 11 10:31:51 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Mon, 11 Sep 2006 10:31:51 +0200 (CEST) Subject: [kupu-checkins] r32137 - in kupu/trunk/kupu: plone/kupu_plone_layer tests Message-ID: <20060911083151.2F26A10086@code0.codespeak.net> Author: duncan Date: Mon Sep 11 10:31:49 2006 New Revision: 32137 Modified: kupu/trunk/kupu/plone/kupu_plone_layer/kupuploneeditor.js kupu/trunk/kupu/tests/test_plone.js Log: Fix two relative link unit tests. Modified: kupu/trunk/kupu/plone/kupu_plone_layer/kupuploneeditor.js ============================================================================== --- kupu/trunk/kupu/plone/kupu_plone_layer/kupuploneeditor.js (original) +++ kupu/trunk/kupu/plone/kupu_plone_layer/kupuploneeditor.js Mon Sep 11 10:31:49 2006 @@ -46,7 +46,8 @@ urlparts[common]==hrefparts[common]) common++; var last = urlparts[common]; - if (common+1 == urlparts.length && (last=='emptypage'||last==pageid)) { + if (common == urlparts.length) { urlparts[common] = '.'; } + else if (common+1 == urlparts.length && (last=='emptypage'||last==pageid)) { urlparts[common] = ''; } // The base and the url have 'common' parts in common. Modified: kupu/trunk/kupu/tests/test_plone.js ============================================================================== --- kupu/trunk/kupu/tests/test_plone.js (original) +++ kupu/trunk/kupu/tests/test_plone.js Mon Sep 11 10:31:49 2006 @@ -71,7 +71,7 @@ this.testRelativeLinks4 = function() { var data = '[1]'; - var expected = '[1]'; + var expected = '[1]'; var base = 'http://localhost:9080/plone/Members/admin/art1'; var actual = this.editor.makeLinksRelative(data, base); From duncan at codespeak.net Mon Sep 11 19:12:08 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Mon, 11 Sep 2006 19:12:08 +0200 (CEST) Subject: [kupu-checkins] r32185 - in kupu/trunk/kupu: doc tests Message-ID: <20060911171208.789D010079@code0.codespeak.net> Author: duncan Date: Mon Sep 11 19:12:05 2006 New Revision: 32185 Modified: kupu/trunk/kupu/doc/PLONE2.txt kupu/trunk/kupu/tests/run_tests.html kupu/trunk/kupu/tests/test_plone.js Log: Corrected documentation for enabling captioning. Added a test for formatting with a tag. Modified: kupu/trunk/kupu/doc/PLONE2.txt ============================================================================== --- kupu/trunk/kupu/doc/PLONE2.txt (original) +++ kupu/trunk/kupu/doc/PLONE2.txt Mon Sep 11 19:12:05 2006 @@ -360,7 +360,8 @@ .. _captioning: Optionally kupu can automatically add captions to images. To enable -this feature you must be linking to an Archetypes based image type, +this feature you must be linking to an Archetypes based image type and +have 'link by uid' enabled in the configuration options, and the field you are editing must invoke the html-to-captioned output transform. @@ -389,7 +390,8 @@ Once you have done this you can configure the portal_transforms tool as follows: * add a new transform id 'captioned_to_html', module - 'Products.PortalTransforms.transforms.identity'. + 'Products.PortalTransforms.transforms.identity' with input type + text/x-html-captioned and output type text/html. * On the portal_transforms policy tab add a policy with output type=text/x-html-safe, uses transforms='html-to-captioned'. Modified: kupu/trunk/kupu/tests/run_tests.html ============================================================================== --- kupu/trunk/kupu/tests/run_tests.html (original) +++ kupu/trunk/kupu/tests/run_tests.html Mon Sep 11 19:12:05 2006 @@ -101,6 +101,10 @@ + Modified: kupu/trunk/kupu/tests/test_plone.js ============================================================================== --- kupu/trunk/kupu/tests/test_plone.js (original) +++ kupu/trunk/kupu/tests/test_plone.js Mon Sep 11 19:12:05 2006 @@ -122,6 +122,17 @@ this.ui.setTextStyle('th'); this.assertEquals(this._cleanHtml(this.body.innerHTML), withheader); } + + this.testSetTextSpanStyle = function() { + var data = '

some text

some more

'; + var expected = '

some text

some more

'; + this.body.innerHTML = data; + this._setSelection(5, null, 14, null, 'textsome'); + var ui = new KupuUI('span-styles'); + ui.editor = this.editor; + ui.setTextStyle('span|highlight'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + } } KupuPloneTestCase.prototype = new SelectionTestCase; From duncan at codespeak.net Tue Sep 12 19:34:15 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Tue, 12 Sep 2006 19:34:15 +0200 (CEST) Subject: [kupu-checkins] r32236 - in kupu/trunk/kupu/plone: . kupu_plone_layer Message-ID: <20060912173415.3251810080@code0.codespeak.net> Author: duncan Date: Tue Sep 12 19:34:12 2006 New Revision: 32236 Modified: kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py kupu/trunk/kupu/plone/plonelibrarytool.py Log: Remove from the default list of banned tags. Modified: kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py ============================================================================== --- kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py (original) +++ kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py Tue Sep 12 19:34:12 2006 @@ -21,7 +21,7 @@ ) EXCLUDED_HTML = [ - {'tags': ('center','span','tt','big','small','s','strike','basefont','font',), + {'tags': ('center','tt','big','small','s','strike','basefont','font',), 'attributes':(), 'keep': 1 }, Modified: kupu/trunk/kupu/plone/plonelibrarytool.py ============================================================================== --- kupu/trunk/kupu/plone/plonelibrarytool.py (original) +++ kupu/trunk/kupu/plone/plonelibrarytool.py Tue Sep 12 19:34:12 2006 @@ -66,7 +66,7 @@ # Tidy up html by exlcluding lots of things. _excluded_html = [ - (('center', 'span', 'tt', 'big', 'small', 's', 'strike', 'basefont', 'font'), ()), + (('center', 'tt', 'big', 'small', 's', 'strike', 'basefont', 'font'), ()), ((), ('dir','lang','valign','halign','border','frame','rules','cellspacing','cellpadding','bgcolor')), (('table','th','td'),('width','height')), ] @@ -504,7 +504,6 @@ installBeforeUnload=None, parastyles=None, refbrowser=None, captioning=None, filterSourceEdit=None, - filterSourceEdit=None, REQUEST=None): """Delete resource types through the ZMI""" self.linkbyuid = int(linkbyuid) From mihxil at codespeak.net Tue Sep 19 10:48:35 2006 From: mihxil at codespeak.net (mihxil at codespeak.net) Date: Tue, 19 Sep 2006 10:48:35 +0200 (CEST) Subject: [kupu-checkins] r32473 - in kupu/trunk/kupu/mmbase: . tools Message-ID: <20060919084835.29BA910082@code0.codespeak.net> Author: mihxil Date: Tue Sep 19 10:48:33 2006 New Revision: 32473 Modified: kupu/trunk/kupu/mmbase/kupustyle.css kupu/trunk/kupu/mmbase/toolboxes.kupu kupu/trunk/kupu/mmbase/tools/empty.jspx Log: introduced the possiblity to indicate that an image must be 'big' Modified: kupu/trunk/kupu/mmbase/kupustyle.css ============================================================================== --- kupu/trunk/kupu/mmbase/kupustyle.css (original) +++ kupu/trunk/kupu/mmbase/kupustyle.css Tue Sep 19 10:48:33 2006 @@ -63,20 +63,23 @@ background-color: #fafafa; } -td { - border: 1px black solid; +.mmxf table.plain td, .mmxf table.data td { + border: 1px gray solid; } + th { border: 1px black solid; } img.image-right { + width: 100px; float: right; margin-right: 0px; margin-left: 1ex; } img.image-left { + width: 100px; float: left; margin-left: 0px; margin-right: 1ex; @@ -95,6 +98,10 @@ float: left; border: solid 1px green; } +img.big { + width: 200px; + height: auto; +} strong, b { color: green; Modified: kupu/trunk/kupu/mmbase/toolboxes.kupu ============================================================================== --- kupu/trunk/kupu/mmbase/toolboxes.kupu (original) +++ kupu/trunk/kupu/mmbase/toolboxes.kupu Tue Sep 19 10:48:33 2006 @@ -23,6 +23,8 @@ + + +

Debug Log

From duncan at codespeak.net Fri Sep 22 13:23:59 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Fri, 22 Sep 2006 13:23:59 +0200 (CEST) Subject: [kupu-checkins] r32574 - in kupu/trunk/kupu: common doc plone plone/kupu_plone_layer plone/kupu_plone_layer/plonekupuimages Message-ID: <20060922112359.5B7151006C@code0.codespeak.net> Author: duncan Date: Fri Sep 22 13:23:55 2006 New Revision: 32574 Modified: kupu/trunk/kupu/common/kupuhelpers.js kupu/trunk/kupu/doc/PLONE2.txt kupu/trunk/kupu/plone/kupu_plone_layer/plonekupuimages/ (props changed) kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py kupu/trunk/kupu/plone/librarytool.py kupu/trunk/kupu/plone/plonedrawers.py kupu/trunk/kupu/plone/plonelibrarytool.py kupu/trunk/kupu/plone/resource_types.pt Log: Fix: Image drawer didn't close properly when inserting an image at the end of a line. Preview configuration now has more fields so images no longer have to use the target object's URL. See PLONE2.txt for a description. Modified: kupu/trunk/kupu/common/kupuhelpers.js ============================================================================== --- kupu/trunk/kupu/common/kupuhelpers.js (original) +++ kupu/trunk/kupu/common/kupuhelpers.js Fri Sep 22 13:23:55 2006 @@ -538,11 +538,11 @@ container.insertBefore(node, afterNode); } else { container.appendChild(node); + afterNode = container.nextSibling; }; } - - range.setEnd(afterNode, 0); - range.setStart(afterNode, 0); + range.setEndAfter(node); + range.collapse(false); } if (selectAfterPlace) { Modified: kupu/trunk/kupu/doc/PLONE2.txt ============================================================================== --- kupu/trunk/kupu/doc/PLONE2.txt (original) +++ kupu/trunk/kupu/doc/PLONE2.txt Fri Sep 22 13:23:55 2006 @@ -293,6 +293,28 @@ be the name of an Archetypes field (in the form 'portal type.field name'). See `Reference Browser`_. +Action urls +~~~~~~~~~~~ + +For any type (but mostly images) you may specify expressions to be +used for the preview in the drawer properties panel, the url to be +inserted for a normal image, and the field to be used to determine +image scales. The defaults are: + + preview + No preview shown by default. Set to + 'string:${object_url}/image_thumb' for an image preview. + object_url for the preview is the actual url of the object. + + normal image + Defaults to 'string:${object_url}'. object_url for the normal + url will be the resolveuid form if uids are being used, + otherwise the actual url. + + fieldname + Defaults to 'image'. N.B. This is a literal string, not a tal + expression. + documentation tab ================= @@ -485,17 +507,14 @@ attributes are recognised: allowed_types - Direct equivalent of Kupu's own resource types. Lists permitted types for the drawer. allowed_types_method - The name of a method on the object which can be called to return the list of types. base_query - Either a dictionary, or the name of a method which returns a dictionary. This dictionary contains search parameters used by libraries. Modified: kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py ============================================================================== --- kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py (original) +++ kupu/trunk/kupu/plone/kupu_plone_layer/sample-kupu-customisation-policy.py Fri Sep 22 13:23:55 2006 @@ -93,9 +93,16 @@ # this picks the wrong preview URL, you might want to change these # expressions. PREVIEW_EXPR = 'string:${object_url}/%s' -PREVIEW = [ { 'portal_type': type, 'expression': PREVIEW_EXPR % image } +PREVIEW = [ { 'portal_type': type, + 'expression': PREVIEW_EXPR % image, + 'normal': None, + 'scalefield': image.split('_',1)[0], + } for (type, image) in tool.getPreviewable() ] -# e.g. PREVIEW=[{'portal_type': 'Image', 'expression':'string:${object_url}/image_thumb'}] +# e.g. PREVIEW=[{'portal_type': 'Image', +# 'expression':'string:${object_url}/image_thumb' +# 'normal': 'string:$object_url', +# 'scalefield': 'image' }] for p in PREVIEW: print p['portal_type'], p['expression'] Modified: kupu/trunk/kupu/plone/librarytool.py ============================================================================== --- kupu/trunk/kupu/plone/librarytool.py (original) +++ kupu/trunk/kupu/plone/librarytool.py Fri Sep 22 13:23:55 2006 @@ -167,15 +167,22 @@ type_map[resource_type] = tuple(portal_types) def updatePreviewActions(self, preview_actions): + """Now a misnomer: actually updates preview, normal, and scaling data""" action_map = {} for a in preview_actions: portal_type = a.get('portal_type', '') - expr = a.get('expression', '') + preview = a.get('expression', '') + normal = a.get('normal', None) + if normal: + normal = Expression(normal) + scalefield = a.get('scalefield', 'image') if not portal_type: continue - action_map[portal_type] = { 'expression': Expression(expr), } - + action_map[portal_type] = { + 'expression': Expression(preview), + 'normal': normal, + 'scalefield': scalefield, } self._preview_actions = action_map def deleteResourceTypes(self, resource_types): @@ -206,3 +213,17 @@ return expr(context) return None + def getNormalUrl(self, portal_type, url): + action_map = getattr(self, '_preview_actions', {}) + if portal_type in action_map: + expr = action_map[portal_type]['normal'] + if expr: + data = { + 'object_url': url, + 'portal_type': portal_type, + 'modules': SecureModuleImporter, + } + context = getEngine().getContext(data) + return expr(context) + return url + Modified: kupu/trunk/kupu/plone/plonedrawers.py ============================================================================== --- kupu/trunk/kupu/plone/plonedrawers.py (original) +++ kupu/trunk/kupu/plone/plonedrawers.py Fri Sep 22 13:23:55 2006 @@ -160,14 +160,14 @@ self.anchor_types = tool.getResourceType('containsanchors').portal_types self.portal_base = self.url_tool.getPortalPath() self.prefix_length = len(self.portal_base)+1 - self.resource_type = tool.getResourceType(resource_type) + self.resource_type = resource_type instance = tool.REQUEST.get('instance', '') if instance: instance = 'instance=%s&' % tool.REQUEST.instance self.srctail = 'kupucollection.xml?'+instance+'resource_type=' + resource_type.name - self.showimagesize = resource_type=='mediaobject' + self.showimagesize = resource_type.name=='mediaobject' # The redirecting url must be absolute otherwise it won't work for # preview when the page is using portal_factory @@ -219,6 +219,7 @@ cache_key = (get_ident(), self.portal_base, portal_type) if not IMAGE_SIZES_CACHE.has_key(cache_key): IMAGE_SIZES_CACHE[cache_key] = {} + imagefield = self.tool.getScaleFieldForType(portal_type) # if getId is not callable, we assume that we have a brain and # need to get the object if not callable(obj.getId): @@ -227,21 +228,21 @@ obj = obj.getObject() if getattr(obj, 'getField', None) is None: return - image_field = obj.getWrappedField('image') + image_field = obj.getWrappedField(imagefield) if image_field is None: return if getattr(image_field, 'getAvailableSizes', None) is None: return image_sizes = image_field.getAvailableSizes(obj) - sizes = [((v[0], v[1]), k) for k,v in image_sizes.items()] + sizes = [(v[0], v[1], k, '%s_%s' % (imagefield,k)) for k,v in image_sizes.items()] sizes.sort() IMAGE_SIZES_CACHE[cache_key] = sizes else: sizes = IMAGE_SIZES_CACHE[cache_key] results = [] - for size, key in sizes: - results.append({'label':"%s (%s, %s)" % (key.capitalize(), size[0], size[1]), - 'uri':"%s/image_%s" % (url, key)}) + for width, height, key, action in sizes: + results.append({'label':"%s (%s, %s)" % (key.capitalize(), width, height), + 'uri':"%s/%s" % (url, action)}) return results def getState(self, review_state): @@ -276,8 +277,9 @@ portal_type = getattr(obj, 'portal_type','') collection = portal_type in self.coll_types + tool = self.tool url = obj.absolute_url() - preview = self.tool.getPreviewUrl(portal_type, url) + preview = tool.getPreviewUrl(portal_type, url) if collection and self.resource_type.allow_browse: src = obj.absolute_url() @@ -289,6 +291,11 @@ if UID and self.linkbyuid: url = self.base+'/resolveuid/%s' % UID + if self.showimagesize: + normal = tool.getNormalUrl(portal_type, url) + else: + normal = url + sizes = self.get_image_sizes(obj, portal_type, url) icon = self.icon(obj.getIcon(1)) @@ -307,7 +314,7 @@ return { 'id': id, - 'url': url, + 'url': normal, 'portal_type': portal_type, 'collection': collection, 'icon': icon, @@ -334,7 +341,8 @@ url = brain.getURL() portal_type = brain.portal_type collection = portal_type in self.coll_types - preview = self.tool.getPreviewUrl(portal_type, url) + tool = self.tool + preview = tool.getPreviewUrl(portal_type, url) # Path for the uid catalog doesn't have the leading '/' path = brain.getPath() @@ -360,6 +368,11 @@ if UID and self.linkbyuid: url = self.base+'/resolveuid/%s' % UID + if self.showimagesize: + normal = tool.getNormalUrl(portal_type, url) + else: + normal = url + sizes = self.get_image_sizes(brain, portal_type, url) icon = self.icon(brain.getIcon) @@ -377,7 +390,7 @@ return { 'id': id, - 'url': url, + 'url': normal, 'portal_type': portal_type, 'collection': collection, 'icon': icon, Modified: kupu/trunk/kupu/plone/plonelibrarytool.py ============================================================================== --- kupu/trunk/kupu/plone/plonelibrarytool.py (original) +++ kupu/trunk/kupu/plone/plonelibrarytool.py Fri Sep 22 13:23:55 2006 @@ -497,6 +497,18 @@ expr = action_map.get(portal_type, {}).get('expression', '') return getattr(expr, 'text', expr) + security.declareProtected(permissions.ManageLibraries, "getNormalViewForType") + def getNormalViewForType(self, portal_type): + action_map = getattr(self, '_preview_actions', {}) + expr = action_map.get(portal_type, {}).get('normal', '') + return getattr(expr, 'text', expr) + + security.declareProtected(permissions.ManageLibraries, "getScaleFieldForType") + def getScaleFieldForType(self, portal_type): + action_map = getattr(self, '_preview_actions', {}) + value = action_map.get(portal_type, {}).get('scalefield', 'image') + return value + security.declareProtected(permissions.ManageLibraries, "configure_kupu") def configure_kupu(self, Modified: kupu/trunk/kupu/plone/resource_types.pt ============================================================================== --- kupu/trunk/kupu/plone/resource_types.pt (original) +++ kupu/trunk/kupu/plone/resource_types.pt Fri Sep 22 13:23:55 2006 @@ -127,33 +127,52 @@ previewable python:[t for t in typeinfos if context.getPreviewForType(t.getId())];"> - Preview URLs + Action URLs Type - URL + URL - + - previewable type + type + preview + tal:attributes="value previewaction" /> + + + + Normal Image + + + + + + fieldname + + @@ -161,10 +180,10 @@ - + - + + preview + + Normal Image + + + + + + fieldname + + + + -   - +   + + Preview is an expression to use for the preview image in the drawer [default is no preview]. + Normal image is an expression to use for the normal view of a mediaobject [string:$object_url]. + Fieldname is the name of the field to use for scaled variants of the mediaobject [image]. + + From duncan at codespeak.net Fri Sep 22 13:45:33 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Fri, 22 Sep 2006 13:45:33 +0200 (CEST) Subject: [kupu-checkins] r32575 - kupu/trunk/kupu/tests Message-ID: <20060922114533.CAD1D10070@code0.codespeak.net> Author: duncan Date: Fri Sep 22 13:45:32 2006 New Revision: 32575 Modified: kupu/trunk/kupu/tests/test_plone.js Log: Unit test for span highlighting was failing on IE (because no quotes round the classname). Modified: kupu/trunk/kupu/tests/test_plone.js ============================================================================== --- kupu/trunk/kupu/tests/test_plone.js (original) +++ kupu/trunk/kupu/tests/test_plone.js Fri Sep 22 13:45:32 2006 @@ -125,12 +125,12 @@ this.testSetTextSpanStyle = function() { var data = '

some text

some more

'; - var expected = '

some text

some more

'; + var expected = '

some text

some more

'; this.body.innerHTML = data; this._setSelection(5, null, 14, null, 'textsome'); var ui = new KupuUI('span-styles'); ui.editor = this.editor; - ui.setTextStyle('span|highlight'); + ui.setTextStyle('span|high light'); this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); } } From duncan at codespeak.net Sat Sep 23 13:04:00 2006 From: duncan at codespeak.net (duncan at codespeak.net) Date: Sat, 23 Sep 2006 13:04:00 +0200 (CEST) Subject: [kupu-checkins] r32605 - in kupu/trunk/kupu: common tests Message-ID: <20060923110400.CD14410071@code0.codespeak.net> Author: duncan Date: Sat Sep 23 13:03:55 2006 New Revision: 32605 Modified: kupu/trunk/kupu/common/kupubasetools.js kupu/trunk/kupu/common/kupueditor.js kupu/trunk/kupu/common/kupuhelpers.js kupu/trunk/kupu/common/kupustyles.css kupu/trunk/kupu/tests/run_tests.html kupu/trunk/kupu/tests/test_kupubasetools.js kupu/trunk/kupu/tests/test_kupuhelpers.js kupu/trunk/kupu/tests/test_plone.js Log: Applied patch from George Lee to support paragraph formatting inside table cells. Modified the style pulldown to distinguish 'Plain Cell' (TD) from 'Normal' (P), and to add a 'No char style' for removing a SPAN. Added a bunch more unit tests for style selection. Still to do: need some way to remove Normal styling inside a table: I plan to add a 'Remove block style' option which can be used anywhere inside a block tag to remove it. Modified: kupu/trunk/kupu/common/kupubasetools.js ============================================================================== --- kupu/trunk/kupu/common/kupubasetools.js (original) +++ kupu/trunk/kupu/common/kupubasetools.js Sat Sep 23 13:03:55 2006 @@ -251,7 +251,10 @@ this.otherstyle = null; this.tablestyles = {}; this.styles = {}; // use an object here so we can use the 'in' operator later on - + var blocktagre = /^(p|div|h.|ul|ol|dl|menu|dir|pre|blockquote|address|center)$/i; + var spanre = /^span\b/i; + var tblre = /^thead|tbody|table|t[rdh]\b/i; + this.initialize = function(editor) { /* initialize the ui like tools */ this.editor = editor; @@ -332,13 +335,16 @@ var options = this.tsselect.options; var parastyles = this.styles; var tablestyles = this.tablestyles; + var styleoptions = []; - tableoptions.push([options[0].text, 'td|']); - tablestyles['td'] = 0; - paraoptions.push([options[0].text, 'p|']); - parastyles['p'] = 0; - while (options.length > 1) { - opt = options[1]; + var normal = ['Normal', 'p|']; + var td = ['Plain Cell', 'td|']; + var nochar = ['No char style', 'span|']; + + var opts = []; + while (options.length) { + opt = options[0]; + options[0] = null; var v = opt.value; if (v.indexOf('|') > -1) { var split = v.split('|'); @@ -346,21 +352,53 @@ } else { v = v.toLowerCase()+"|"; }; - var optarray = [opt.text,v]; - if (/^thead|tbody|table|t[rdh]\b/i.test(v)) { + var optarray = [opt.text, v]; + if (v=='td|') { + td = optarray; + } else if (v=='p|') { + normal = optarray; + } else if (v=='span|') { + nochar = optarray; + } else { + opts.push([opt.text,v]); + } + } + tableoptions.push(td); + tablestyles[td[1]] = 0; + paraoptions.push(normal); + parastyles[normal[1]] = 0; + styleoptions.push(nochar); + + for (i = 0; i < opts.length; i++) { + optarray = opts[i]; + v = optarray[1]; + + if (spanre.test(v)) { + styleoptions.push(optarray); + } else if (tblre.test(v)) { + tablestyles[v] = tableoptions.length; tableoptions.push(optarray); - tablestyles[v] = tableoptions.length-1; } else { + parastyles[v] = paraoptions.length; paraoptions.push(optarray); - parastyles[v] = paraoptions.length-1; - if (/^span\b/i.test(v)) { - tableoptions.push(optarray); - tablestyles[v] = tableoptions.length-1; - }; }; - options[1] = null; + }; + if (styleoptions.length > 1) { + for (var i = 0; i < styleoptions.length; i++) { + optarray = styleoptions[i]; + parastyles[optarray[1]] = paraoptions.length; + paraoptions.push(optarray); + } + }; + if (tableoptions.length < 2) { + tableoptions[0] = null; + } + // tableoptions needs paraoptions appended + for (var i = 0; i < paraoptions.length; i++) { + optarray = paraoptions[i]; + tablestyles[optarray[1]] = tableoptions.length; + tableoptions.push(optarray); } - options[0] = null; } // Remove otherstyle and switch to appropriate style set. @@ -383,7 +421,7 @@ opt.text = valid[i][0]; var v = valid[i][1]; opt.value = v; - opt.className=(/^span\b/i.test(v))?"kupuCharStyle":"kupuParaStyle"; + opt.className=(tblre.test(v))?"kupuTableStyle":(spanre.test(v))?"kupuCharStyle":"kupuParaStyle"; options.add(opt); } select.selectedIndex = 0; @@ -410,8 +448,22 @@ var options = this.tsselect.options; this.styletag = undefined; this.classname = ''; + + // Set the table state correctly this.intable = false; + while(currnode) { + var tag = currnode.nodeName; + if (/^body$/i.test(tag)) break; + if (tblre.test(tag)) { + this.intable = true; + break; + }; + currnode = currnode.parentNode; + }; + var styles = this.intable? this.tablestyles : this.styles; + + currnode = node; while (currnode) { var tag = currnode.nodeName.toLowerCase(); @@ -423,15 +475,14 @@ } break; } - if (/^span$/.test(tag)) { - index = this.setIndex(currnode, tag, index, this.styles); + if (spanre.test(tag)) { + index = this.setIndex(currnode, tag, index, styles); if (index > 0) return index; // span takes priority - } else if (/^(p|div|h.|ul|ol|dl|menu|dir|pre|blockquote|address|center)$/.test(tag)) { - index = this.setIndex(currnode, tag, index, this.styles); - } else if (/^thead|tbody|table|t[rdh]$/.test(tag)) { - this.intable = true; - index = this.setIndex(currnode, tag, index, this.tablestyles); - + } else if (blocktagre.test(tag)) { + index = this.setIndex(currnode, tag, index, styles); + } else if (tblre.test(tag)) { + if (index > 0) return index; // block or span takes priority. + index = this.setIndex(currnode, tag, index, styles); if (index > 0 || tag=='table') { return index; // Stop processing if in a table } @@ -473,7 +524,6 @@ if (index===undefined) { index = this.nodeStyle(selNode); } - this.enableOptions(this.intable); if (index < 0 || mixed) { @@ -519,50 +569,79 @@ }; } - this._cleanCell = function(eltype, classname) { - var selNode = this.editor.getSelectedNode(); + this._cleanCell = function(eltype, classname, strip) { + var selNode = this.editor.getSelectedNode(true); var el = this.editor.getNearestParentOfType(selNode, eltype); if (!el) { // Maybe changing type el = this.editor.getNearestParentOfType(selNode, eltype=='TD'?'TH':'TD'); } - if (!el) return; - // Remove formatted div or p from a cell - var node, nxt, n; - for (node = el.firstChild; node;) { - if (/DIV|P/.test(node.nodeName)) { - for (var n = node.firstChild; n;) { - var nxt = n.nextSibling; - el.insertBefore(n, node); // Move nodes out of div - n = nxt; + //either the selection is inside a cell, spans cells, or includes + //a collection of cells + + //first, if contained in a cell + + if (el) { + if (eltype != el.tagName) { + // Change node type. + var node = el.ownerDocument.createElement(eltype); + var parent = el.parentNode; + parent.insertBefore(node, el); + while (el.firstChild) { + node.appendChild(el.firstChild); } - nxt = node.nextSibling; - el.removeChild(node); - node = nxt; - } else { - node = node.nextSibling; + parent.removeChild(el); + el = node; } - } - if (eltype != el.tagName) { - // Change node type. - var node = el.ownerDocument.createElement(eltype); - var parent = el.parentNode; - parent.insertBefore(node, el); - while (el.firstChild) { - node.appendChild(el.firstChild); - } - parent.removeChild(el); - el = node; - } - // now set the classname - if (classname) { - el.className = classname; + // now set the classname + this._setClass(el, classname); + if (strip && el.childNodes.length==1) { + var node = el.firstChild; + if (blocktagre.test(node.nodeName)) { + for (var n = node.firstChild; n;) { + var nxt = n.nextSibling; + el.insertBefore(n, node); // Move nodes out of block + n = nxt; + }; + nxt = node.nextSibling; + el.removeChild(node); + node = nxt; + }; + }; } else { - el.removeAttribute("class"); - el.removeAttribute("className"); - } + //otherwise, find all cells that intersect the selection + var selection = this.editor.getSelection(); + var tdNodes = selNode.getElementsByTagName('TD'); + var thNodes = selNode.getElementsByTagName('TH'); + var cellNodes = Array(); + for (var i = 0; i < tdNodes.length; i++) { + cellNodes.push(tdNodes.item(i)); + }; + for (var i = 0; i < thNodes.length; i++) { + cellNodes.push(thNodes.item(i)); + }; + + for (var i = 0; i < cellNodes.length; i++) { + el = cellNodes[i]; + + if(selection.intersectsNode(el)) { + if (eltype != el.tagName) { + // Change node type. + var node = el.ownerDocument.createElement(eltype); + var parent = el.parentNode; + parent.insertBefore(node, el); + while (el.firstChild) { + node.appendChild(el.firstChild); + }; + parent.removeChild(el); + el = node; + }; + this._setClass(el, classname); + } + } + } } this._setClass = function(el, classname) { @@ -607,7 +686,7 @@ if (this.editor.getBrowserName() == 'IE') { command = '<' + eltype + '>'; }; - if (/T[RDH]/.test(eltype)) { + if (tblre.test(eltype)) { this._cleanCell(eltype, classname); } else if (eltype=='SPAN') { doc.execCommand('removeformat', null); @@ -649,7 +728,7 @@ doc.execCommand('formatblock', command); // now get a reference to the element just added - var selNode = this.editor.getSelectedNode(); + var selNode = this.editor.getSelectedNode(true); var el = this.editor.getNearestParentOfType(selNode, eltype); if (el) { this._setClass(el, classname); @@ -1695,7 +1774,7 @@ // Remove formatted div or p from a cell var node, nxt, n; for (node = el.firstChild; node;) { - if (/DIV|P/.test(node.nodeName)) { + if (/^DIV|P$/i.test(node.nodeName)) { for (var n = node.firstChild; n;) { var nxt = n.nextSibling; el.insertBefore(n, node); // Move nodes out of div Modified: kupu/trunk/kupu/common/kupueditor.js ============================================================================== --- kupu/trunk/kupu/common/kupueditor.js (original) +++ kupu/trunk/kupu/common/kupueditor.js Sat Sep 23 13:03:55 2006 @@ -363,9 +363,12 @@ return this.getDocument().getSelection(); }; - this.getSelectedNode = function() { + this.getSelectedNode = function(allowmulti) { /* returns the selected node (read: parent) or none */ - return this.getSelection().parentElement(); + /* if allowmulti is true, returns the parent of all ranges in the + selection (in the rare case that selection has more than one + range) */ + return this.getSelection().parentElement(allowmulti); }; this.getNearestParentOfType = function(node, type) { @@ -832,3 +835,4 @@ } } + Modified: kupu/trunk/kupu/common/kupuhelpers.js ============================================================================== --- kupu/trunk/kupu/common/kupuhelpers.js (original) +++ kupu/trunk/kupu/common/kupuhelpers.js Sat Sep 23 13:03:55 2006 @@ -749,7 +749,7 @@ return length; }; - this.parentElement = function() { + this.parentElement = function(allowmulti) { /* return the selected node (or the node containing the selection) */ // XXX this should be on a range object if (this.selection.rangeCount == 0) { @@ -759,45 +759,114 @@ }; } else { var range = this.selection.getRangeAt(0); - var parent = range.commonAncestorContainer; + var parent = this.parentElementOfRange(range); + if( allowmulti ) { + var numRanges = this.selection.rangeCount; + for( var i = 1; i < numRanges; i = i + 1 ) + { + var parent1 = parent; + var parent2 = null; + var range1 = this.document.getDocument().createRange(); + var range2 = this.document.getDocument().createRange(); + + var parent2 = this.parentElementOfRange(this.selection.getRangeAt(i)); - // the following deals with cases where only a single child is - // selected, e.g. after a click on an image - var inv = range.compareBoundaryPoints(Range.START_TO_END, range) < 0; - var startNode = inv ? range.endContainer : range.startContainer; - var startOffset = inv ? range.endOffset : range.startOffset; - var endNode = inv ? range.startContainer : range.endContainer; - var endOffset = inv ? range.startOffset : range.endOffset; - - var selectedChild = null; - var child = parent.firstChild; - while (child) { - // XXX the additional conditions catch some invisible - // intersections, but still not all of them - if (range.intersectsNode(child) && - !(child == startNode && startOffset == child.length) && - !(child == endNode && endOffset == 0)) { - if (selectedChild) { - // current child is the second selected child found - selectedChild = null; - break; + range1.selectNode(parent1); + range2.selectNode(parent2); + + if( range1.compareBoundaryPoints(Range.START_TO_START, range2) <= 0 + && range1.compareBoundaryPoints(Range.END_TO_END, range2) >= 0 ) { + //parent1 contains parent2 + parent = parent1; + } else if( range1.compareBoundaryPoints(Range.START_TO_START, range2) >= 0 + && range1.compareBoundaryPoints(Range.END_TO_END, range2) <= 0 ) { + //parent2 contains parent1 + parent = parent2; + } else if( range1.compareBoundaryPoints(Range.START_TO_END, range2) <= 0 ) { + //parent1 comes before parent2 + //commonAncestorContainer returns the node parent if a range is + //just one node, which we don't want; but since parent1 + //and parent2 are different, their range is not just + //one node + var coverRange = this.document.getDocument().createRange(); + coverRange.setStartBefore(parent1); + coverRange.setEndAfter(parent2); + parent = coverRange.commonAncestorContainer; } else { - // current child is the first selected child found - selectedChild = child; + //parent2 comes before parent1 + //commonAncestorContainer returns the node parent if a range is + //just one node, which we don't want; but since parent1 + //and parent2 are different, their range is not just + //one node + var coverRange = this.document.getDocument().createRange(); + coverRange.setStartBefore(parent2); + coverRange.setEndAfter(parent1); + parent = coverRange.commonAncestorContainer; }; - } else if (selectedChild) { - // current child is after the selection - break; }; - child = child.nextSibling; }; - if (selectedChild) { - parent = selectedChild; + }; + + if (parent.nodeType == Node.TEXT_NODE) { + parent = parent.parentNode; + }; + return parent; + }; + + this.parentElementOfRange = function(range) { + if( range.compareBoundaryPoints(Range.START_TO_END, range) < 0 ) { + var startNode = range.endContainer; + var startOffset = range.endOffset; + var endNode = range.startContainer; + var endOffset = range.startOffset; + range.setStart( startNode, startOffset ); + range.setEnd( endNode, endOffset ); + } + + var parent = range.commonAncestorContainer; + + // if there is only a single node selected, e.g. after a click on + // an image, then this node itself should be returned as the + // parentElement. however, in this case, "parent" is the selected + // node's parent. the following searches if any other node + // intersects the selection range; if not, then the selected node + // is set to the parentElement. + var inv = range.compareBoundaryPoints(Range.START_TO_END, range) < 0; + var startNode = inv ? range.endContainer : range.startContainer; + var startOffset = inv ? range.endOffset : range.startOffset; + var endNode = inv ? range.startContainer : range.endContainer; + var endOffset = inv ? range.startOffset : range.endOffset; + + var selectedChild = null; + var child = parent.firstChild; + while (child) { + if (range.intersectsNode(child) && + !(child == startNode && startOffset == child.length) && + !(child == endNode && endOffset == 0)) { + if (selectedChild) { + // current child is the second node found that + // intersects the selection, so commonAncestorContainer + // is the correct parentElement to use + selectedChild = null; + break; + } else { + // current child is the first selected child found + selectedChild = child; + }; + } else if (selectedChild) { + // current child is after the selection + break; }; + child = child.nextSibling; + }; + + if (selectedChild) { + parent = selectedChild; }; if (parent.nodeType == Node.TEXT_NODE) { parent = parent.parentNode; }; + return parent; }; @@ -901,6 +970,15 @@ selection.removeAllRanges(); selection.addRange(range); } + + this.intersectsNode = function(node) { + for(var i = 0; i < this.selection.rangeCount; i++ ) { + if( this.selection.getRangeAt(i).intersectsNode(node) ) { + return true; + } + }; + return false; + }; }; MozillaSelection.prototype = new BaseSelection; @@ -1068,7 +1146,7 @@ return length; }; - this.parentElement = function() { + this.parentElement = function(allowmulti) { /* return the selected node (or the node containing the selection) */ // XXX this should be on a range object if (this.selection.type == 'Control') { @@ -1144,6 +1222,19 @@ this.toString = function() { return this.selection.createRange().text; }; + + this.intersectsNode = function(node) { + var noderange = doc.body.createTextRange(); + noderange.moveToElementText(node); + + var selrange = this.selection.createRange(); + + if((selrange.compareEndPoints('StartToStart', noderange) <= 0 && selrange.compareEndPoints('EndToStart', noderange) > 0) + ||(selrange.compareEndPoints('StartToStart', noderange) > 0 && selrange.compareEndPoints('StartToEnd', noderange) < 0)) { + return true; + } + return false; + }; }; IESelection.prototype = new BaseSelection; Modified: kupu/trunk/kupu/common/kupustyles.css ============================================================================== --- kupu/trunk/kupu/common/kupustyles.css (original) +++ kupu/trunk/kupu/common/kupustyles.css Sat Sep 23 13:03:55 2006 @@ -279,6 +279,10 @@ filter:alpha(opacity=50); } +.kupuTableStyle { + font-style: underline; + background-color: #82feff; +} .kupuCharStyle { font-style: italic; background-color: #feff82; Modified: kupu/trunk/kupu/tests/run_tests.html ============================================================================== --- kupu/trunk/kupu/tests/run_tests.html (original) +++ kupu/trunk/kupu/tests/run_tests.html Sat Sep 23 13:03:55 2006 @@ -94,17 +94,21 @@
- - +
+ + +
Modified: kupu/trunk/kupu/tests/test_kupubasetools.js ============================================================================== --- kupu/trunk/kupu/tests/test_kupubasetools.js (original) +++ kupu/trunk/kupu/tests/test_kupubasetools.js Sat Sep 23 13:03:55 2006 @@ -8,8 +8,6 @@ * *****************************************************************************/ -// $Id$ - function KupuUITestCase() { this.name = 'KupuUITestCase'; SelectionTestCase.apply(this); @@ -18,10 +16,70 @@ this.setUp = function() { this.base_setUp(); this.editor = new KupuEditor(this.kupudoc, {}, null); + this.preserve = document.getElementById('preserve-this-div').innerHTML; this.ui = new KupuUI('kupu-tb-styles'); this.ui.editor = this.editor; }; + this.tearDown = function() { + document.getElementById('preserve-this-div').innerHTML = this.preserve; + }; + + this._selectTableCells = function(indices, verificationString) { + var tableNodes = this.body.getElementsByTagName("table"); + var cellNodes = new Array(); + + var curNode = null; + var direction = null; + var foundNext = null; + + for(var i = 0; i < tableNodes.length; i = i + 1) { + curNode = tableNodes[i].firstChild; + //what if no child? + direction = 'down'; + + while( curNode.nodeName.toLowerCase() != 'table' ) { + /*if(indices[1]==2) { + alert(curNode.nodeName); + alert(curNode.innerHTML); + }*/ + if( curNode.nodeName.toLowerCase() == 'td' || curNode.nodeName.toLowerCase() == 'th' ) { + cellNodes.push(curNode); + }; + + foundNext = false; + while( !foundNext && curNode.nodeName.toLowerCase() != 'table' ) { + if( direction == 'right' ) { + if( curNode.nextSibling ) { + curNode = curNode.nextSibling; + direction = 'down'; + foundNext = true; + } else { + curNode = curNode.parentNode; + }; + } else if( direction == 'down' ) { + if( curNode.firstChild ) { + curNode = curNode.firstChild; + foundNext = true; + } else { + direction = 'right'; + }; + }; + }; + }; + }; + + this.selection.selection.removeAllRanges(); + for(var i = 0; i < indices.length; i = i + 1) { + var range = document.createRange(); + range.selectNode(cellNodes[indices[i]]); + this.selection.selection.addRange(range); + }; + + this.assertEquals('"'+this.selection.toString().replace(/\r|\n/g, '')+'"', + '"'+verificationString+'"'); + }; + this.test_updateState = function() { this.body.innerHTML = '

foo

bar

baz

'; var node = this.body.getElementsByTagName('pre')[0]; @@ -33,6 +91,36 @@ this.assertEquals(this.ui.tsselect.selectedIndex, 3); }; + this.updateStateTest = function(html, start, end, verify, ieskew, label) { + this.body.innerHTML = html; + this.ui.cleanStyles(); + this.ui.enableOptions(false); + this._setSelection(start, null, end, null, verify, ieskew); + node = this.editor.getSelectedNode(); + this.ui.updateState(node); + var select = this.ui.tsselect; + this.assertEquals(select.options[select.selectedIndex].text, label); + }; + this.test_updateState2 = function() { + this.updateStateTest('
foobar
', + 1, 3, 'oo', 1, "Plain Cell"); + }; + + this.test_updateState3 = function() { + this.updateStateTest('
foobar
', + 4, 6, 'ar', 2, "Odd Cell"); + }; + + this.test_updateState4 = function() { + this.updateStateTest('
foobaz
', + 4, 6, 'az', 1, "Highlight"); + } + + this.test_updateState5 = function() { + this.updateStateTest('
foo
baz
', + 4, 6, 'az', 2, "Caption"); + } + this.test_setTextStyle = function() { this.body.innerHTML = '

foo

bar

baz

'; // select |bar| @@ -41,10 +129,107 @@ this.assertEquals(this._cleanHtml(this.body.innerHTML), '

foo

bar

baz

'); }; + + this.test_setTextStyle_ParaStyle_SingleTableCell = function() { + //Apply a paragraph style inside a table cell + var data = '
bar
'; + var expected = '

bar

'; + this.body.innerHTML = data; + this._setSelection(0, null, 3, null, 'bar', 1); + this.ui.setTextStyle('h1|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + }; + +// This test doesn't work yet: the intention is that setting text style +// to '' will remove a block style round the current selection. +// this.test_removeTextStyle_ParaStyle_SingleTableCell = function() { +// //Remove a paragraph style inside a table cell +// var data = '

bar

'; +// var expected = '
bar
'; +// this.body.innerHTML = data; +// this._setSelection(0, null, 3, null, 'bar', 1); +// this.ui.setTextStyle(''); +// this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); +// }; + + this.test_setTextStyle_ParaStyleThenCellStyle_SingleTableCell = function() { + //Change the paragraph style inside a table cell, then change the cell + //style to a td with a class + var data = '
bar
'; + var expected = '
bar
'; + var withcellstyle = '
bar
'; + this.body.innerHTML = data; + this._setSelection(0, null, 3, null, 'bar', 1); + this.ui.setTextStyle('div|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + this._setSelection(0, null, 3, null, 'bar', 1); + this.ui.setTextStyle('td|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), withcellstyle); + }; + + this.test_setTextStyle_TableHeaderThenParaStyle_SingleTableCell = function() { + //Apply a table header style to a cell, then a paragraph style + data = '
bar
'; + expected = '
bar
'; + withblockstyle = '
bar
'; + this.body.innerHTML = data; + this._setSelection(0, null, 3, null, 'bar', 1); + this.ui.setTextStyle('th|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + this._setSelection(0, null, 3, null, 'bar', 1); + this.ui.setTextStyle('div|te st'); + if (_SARISSA_IS_IE) { + this.assertEquals(this._cleanHtml(this.body.innerHTML), withblockstyle); + } else { + // Firefox doesn't give us the answer we want + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + } + }; + + this.test_setTextStyle_ParaStyle_AdjacentCells = function() { + //Change the paragraph style including *class*, when the selection + //covers two adjacent table cells + data = '
foobar
'; + expected = '

foo

bar

'; + this.body.innerHTML = data; + if( _SARISSA_IS_IE ) { + this._setSelection(1, null, 8, null, 'foobar'); + } else { + this._selectTableCells(new Array(0,1),'foo\tbar'); + }; + this.ui.setTextStyle('h1|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + }; + + this.test_setTextStyle_SetCellStyle_Column = function() { + //Apply a table cell (td) style, *with class*, on a column of cells -- + //only available with Mozilla + data = '
foofoz
barbaz
'; + expected = '
foofoz
barbaz
' + if (!_SARISSA_IS_IE) { + this.body.innerHTML = data; + this._selectTableCells(new Array(0,2),'foo\tbar'); + this.ui.setTextStyle('td|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + }; + }; + + this.test_setTextStyle_ParaStyle_Column = function() { + //Apply a paragraph style, *with class*, on a column of cells -- only + //available with Mozilla + data = '
foofoz
barbaz
'; + expected = '

foo

foz

bar

baz
' + if (!_SARISSA_IS_IE) { + this.body.innerHTML = data; + this._selectTableCells(new Array(0,2),'foo\tbar'); + this.ui.setTextStyle('h1|te st'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); + }; + }; - this.XXXtest_setTextStyleReplacingDiv = function() { + this.test_setTextStyleReplacingDiv = function() { this.body.innerHTML = '

foo

bar

baz

'; - // select |bar| + // select |bar| this._setSelection(4, null, 7, null, 'bar'); this.ui.setTextStyle('h1'); this.assertEquals(this._cleanHtml(this.body.innerHTML), Modified: kupu/trunk/kupu/tests/test_kupuhelpers.js ============================================================================== --- kupu/trunk/kupu/tests/test_kupuhelpers.js (original) +++ kupu/trunk/kupu/tests/test_kupuhelpers.js Sat Sep 23 13:03:55 2006 @@ -62,10 +62,14 @@ }; this._setSelection = function(startOffset, startNextNode, endOffset, - endNextNode, verificationString) { + endNextNode, verificationString, ieskew) { var element = this.body; var innerSelection = this.selection.selection; if (_SARISSA_IS_IE) { + if (ieskew) { + startOffset += ieskew; + endOffset += ieskew; + }; var range = innerSelection.createRange(); var endrange = innerSelection.createRange(); range.moveToElementText(element); Modified: kupu/trunk/kupu/tests/test_plone.js ============================================================================== --- kupu/trunk/kupu/tests/test_plone.js (original) +++ kupu/trunk/kupu/tests/test_plone.js Sat Sep 23 13:03:55 2006 @@ -110,17 +110,18 @@ var data = '
test
'; // select ................es................... var expected = '
test
'; - var withheader = '
test
'; + var withheader = '
test
'; this.body.innerHTML = data; var idx = _SARISSA_IS_IE ? 2 : 1; this._setSelection(idx, null, idx+2, null, 'es'); this.ui.setTextStyle('div|te st'); // Space in class forces IE to put it in quotes! this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); this._setSelection(idx, null, idx+2, null, 'es'); - this.ui.setTextStyle('td'); - this.assertEquals(this._cleanHtml(this.body.innerHTML), data); this.ui.setTextStyle('th'); this.assertEquals(this._cleanHtml(this.body.innerHTML), withheader); + this._setSelection(idx, null, idx+2, null, 'es'); + this.ui.setTextStyle('td'); + this.assertEquals(this._cleanHtml(this.body.innerHTML), expected); } this.testSetTextSpanStyle = function() { From mihxil at codespeak.net Fri Sep 29 10:47:13 2006 From: mihxil at codespeak.net (mihxil at codespeak.net) Date: Fri, 29 Sep 2006 10:47:13 +0200 (CEST) Subject: [kupu-checkins] r32727 - kupu/trunk/kupu/mmbase Message-ID: <20060929084713.7337610036@code0.codespeak.net> Author: mihxil Date: Fri Sep 29 10:47:12 2006 New Revision: 32727 Modified: kupu/trunk/kupu/mmbase/kupustyle.css Log: color is more specific in mmxf.css. but stil want to override Modified: kupu/trunk/kupu/mmbase/kupustyle.css ============================================================================== --- kupu/trunk/kupu/mmbase/kupustyle.css (original) +++ kupu/trunk/kupu/mmbase/kupustyle.css Fri Sep 29 10:47:12 2006 @@ -152,7 +152,7 @@ font-style: normal; } div.quote { - background-color: #fcc; + background-color: #fcc !important; font-style: italic; }