Compare commits
2 commits
Author | SHA1 | Date | |
---|---|---|---|
eeab12f6d9 | |||
89b9b33b60 |
14
.gitignore
vendored
|
@ -1,14 +1,4 @@
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
.project
|
||||||
*.swp
|
.pydevproject
|
||||||
dist/
|
|
||||||
var/
|
|
||||||
*.egg-info
|
|
||||||
*.project
|
|
||||||
*.pydevproject
|
|
||||||
*.ropeproject
|
|
||||||
*.sublime-project
|
|
||||||
*.sublime-workspace
|
|
||||||
.env
|
|
||||||
.settings
|
.settings
|
||||||
adminuser.zcml
|
|
||||||
|
|
|
@ -6,13 +6,8 @@ $Id$
|
||||||
1.1
|
1.1
|
||||||
---
|
---
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
- provide controlling of rendering macro via field instance method getRenderer()
|
|
||||||
- add getRelations() method to child relation set
|
|
||||||
=======
|
|
||||||
- use targetView entry in request annotations for calling views declared
|
- use targetView entry in request annotations for calling views declared
|
||||||
for adapted concept map objects (i.e. type interfaces)
|
for adapted concept map objects (i.e. type interfaces)
|
||||||
>>>>>>> master
|
|
||||||
- Lobo layout: provide new part: image grid; make sure image is not repeated if
|
- Lobo layout: provide new part: image grid; make sure image is not repeated if
|
||||||
it already appears in header part
|
it already appears in header part
|
||||||
- new special view 'listsubobjects' for nodes
|
- new special view 'listsubobjects' for nodes
|
||||||
|
|
21
LICENSE
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (C) 2023 cyberconcepts.org team
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
222
LICENSE.GPL
Normal file
|
@ -0,0 +1,222 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
11
MANIFEST.in
|
@ -1,11 +0,0 @@
|
||||||
global-include *.cfg
|
|
||||||
global-include *.css *.js
|
|
||||||
global-include *.gif *.jpg *.png
|
|
||||||
global-include *.dmp
|
|
||||||
global-include *.md *.txt
|
|
||||||
global-include *.mo *.po *.pot
|
|
||||||
global-include *.pdf
|
|
||||||
global-include *.pt
|
|
||||||
global-include *.zcml
|
|
||||||
|
|
||||||
graft loops/integrator/testdata
|
|
|
@ -1,7 +0,0 @@
|
||||||
# Introduction
|
|
||||||
|
|
||||||
This is the main part of the code of the semantic
|
|
||||||
web application platform *loops*, based on
|
|
||||||
Zope 3 / bluebream.
|
|
||||||
|
|
||||||
More information: see https://www.cyberconcepts.org.
|
|
|
@ -23,7 +23,7 @@ with lower-level aspects like type or state management.
|
||||||
|
|
||||||
Let's also import some common stuff needed later.
|
Let's also import some common stuff needed later.
|
||||||
|
|
||||||
>>> from loops.common import adapted, baseObject
|
>>> from loops.common import adapted
|
||||||
>>> from loops.setup import addAndConfigureObject
|
>>> from loops.setup import addAndConfigureObject
|
||||||
|
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ top-level loops container and a concept manager:
|
||||||
>>> cc1 = Concept()
|
>>> cc1 = Concept()
|
||||||
>>> concepts['cc1'] = cc1
|
>>> concepts['cc1'] = cc1
|
||||||
>>> cc1.title
|
>>> cc1.title
|
||||||
''
|
u''
|
||||||
>>> loopsRoot.getLoopsUri(cc1)
|
>>> loopsRoot.getLoopsUri(cc1)
|
||||||
'.loops/concepts/cc1'
|
'.loops/concepts/cc1'
|
||||||
|
|
||||||
>>> cc2 = Concept('Zope 3')
|
>>> cc2 = Concept(u'Zope 3')
|
||||||
>>> concepts['cc2'] = cc2
|
>>> concepts['cc2'] = cc2
|
||||||
>>> cc2.title
|
>>> cc2.title
|
||||||
'Zope 3'
|
u'Zope 3'
|
||||||
|
|
||||||
Now we want to relate the second concept to the first one.
|
Now we want to relate the second concept to the first one.
|
||||||
|
|
||||||
|
@ -73,11 +73,11 @@ ConceptRelation):
|
||||||
We can now ask our concepts for their related child and parent concepts:
|
We can now ask our concepts for their related child and parent concepts:
|
||||||
|
|
||||||
>>> [getName(c) for c in cc1.getChildren()]
|
>>> [getName(c) for c in cc1.getChildren()]
|
||||||
['cc2']
|
[u'cc2']
|
||||||
>>> len(cc1.getParents())
|
>>> len(cc1.getParents())
|
||||||
0
|
0
|
||||||
>>> [getName(p) for p in cc2.getParents()]
|
>>> [getName(p) for p in cc2.getParents()]
|
||||||
['cc1']
|
[u'cc1']
|
||||||
|
|
||||||
>>> len(cc2.getChildren())
|
>>> len(cc2.getChildren())
|
||||||
0
|
0
|
||||||
|
@ -90,24 +90,24 @@ a special predicate 'hasType'.
|
||||||
>>> typeObject = concepts['type']
|
>>> typeObject = concepts['type']
|
||||||
>>> typeObject.setConceptType(typeObject)
|
>>> typeObject.setConceptType(typeObject)
|
||||||
>>> typeObject.getConceptType().title
|
>>> typeObject.getConceptType().title
|
||||||
'Type'
|
u'Type'
|
||||||
|
|
||||||
>>> concepts['unknown'] = Concept('Unknown Type')
|
>>> concepts['unknown'] = Concept(u'Unknown Type')
|
||||||
>>> unknown = concepts['unknown']
|
>>> unknown = concepts['unknown']
|
||||||
>>> unknown.setConceptType(typeObject)
|
>>> unknown.setConceptType(typeObject)
|
||||||
>>> unknown.getConceptType().title
|
>>> unknown.getConceptType().title
|
||||||
'Type'
|
u'Type'
|
||||||
|
|
||||||
>>> cc1.setConceptType(unknown)
|
>>> cc1.setConceptType(unknown)
|
||||||
>>> cc1.getConceptType().title
|
>>> cc1.getConceptType().title
|
||||||
'Unknown Type'
|
u'Unknown Type'
|
||||||
|
|
||||||
>>> concepts['topic'] = Concept('Topic')
|
>>> concepts['topic'] = Concept(u'Topic')
|
||||||
>>> topic = concepts['topic']
|
>>> topic = concepts['topic']
|
||||||
>>> topic.setConceptType(typeObject)
|
>>> topic.setConceptType(typeObject)
|
||||||
>>> cc1.setConceptType(topic)
|
>>> cc1.setConceptType(topic)
|
||||||
>>> cc1.getConceptType().title
|
>>> cc1.getConceptType().title
|
||||||
'Topic'
|
u'Topic'
|
||||||
|
|
||||||
We get a list of types using the ConceptTypeSourceList.
|
We get a list of types using the ConceptTypeSourceList.
|
||||||
In order for the type machinery to work we first have to provide a
|
In order for the type machinery to work we first have to provide a
|
||||||
|
@ -124,7 +124,7 @@ type manager.
|
||||||
>>> from loops.concept import ConceptTypeSourceList
|
>>> from loops.concept import ConceptTypeSourceList
|
||||||
>>> types = ConceptTypeSourceList(cc1)
|
>>> types = ConceptTypeSourceList(cc1)
|
||||||
>>> sorted(t.title for t in types)
|
>>> sorted(t.title for t in types)
|
||||||
['Customer', 'Domain', 'Predicate', 'Topic', 'Type', 'Unknown Type']
|
[u'Customer', u'Domain', u'Predicate', u'Topic', u'Type', u'Unknown Type']
|
||||||
|
|
||||||
Using a PredicateSourceList we can retrieve a list of the available
|
Using a PredicateSourceList we can retrieve a list of the available
|
||||||
predicates.
|
predicates.
|
||||||
|
@ -136,7 +136,7 @@ Note that the 'hasType' predicate is suppressed from this list as the
|
||||||
corresponding relation is only assigned via the conceptType attribute:
|
corresponding relation is only assigned via the conceptType attribute:
|
||||||
|
|
||||||
>>> sorted(t.title for t in predicates)
|
>>> sorted(t.title for t in predicates)
|
||||||
['subobject']
|
[u'subobject']
|
||||||
|
|
||||||
Concept Views
|
Concept Views
|
||||||
-------------
|
-------------
|
||||||
|
@ -146,7 +146,7 @@ Concept Views
|
||||||
|
|
||||||
>>> children = list(view.children())
|
>>> children = list(view.children())
|
||||||
>>> [c.title for c in children]
|
>>> [c.title for c in children]
|
||||||
['Zope 3']
|
[u'Zope 3']
|
||||||
|
|
||||||
The token attribute provided with the items returned by the children() and
|
The token attribute provided with the items returned by the children() and
|
||||||
parents() methods identifies identifies not only the item itself but
|
parents() methods identifies identifies not only the item itself but
|
||||||
|
@ -159,14 +159,14 @@ of URIs to item and the predicate of the relationship:
|
||||||
There is also a concept configuration view that allows updating the
|
There is also a concept configuration view that allows updating the
|
||||||
underlying context object:
|
underlying context object:
|
||||||
|
|
||||||
>>> cc3 = Concept('loops for Zope 3')
|
>>> cc3 = Concept(u'loops for Zope 3')
|
||||||
>>> concepts['cc3'] = cc3
|
>>> concepts['cc3'] = cc3
|
||||||
>>> view = ConceptConfigureView(cc1,
|
>>> view = ConceptConfigureView(cc1,
|
||||||
... TestRequest(action='assign', tokens=['.loops/concepts/cc3']))
|
... TestRequest(action='assign', tokens=['.loops/concepts/cc3']))
|
||||||
>>> view.update()
|
>>> view.update()
|
||||||
True
|
True
|
||||||
>>> sorted(c.title for c in cc1.getChildren())
|
>>> sorted(c.title for c in cc1.getChildren())
|
||||||
['Zope 3', 'loops for Zope 3']
|
[u'Zope 3', u'loops for Zope 3']
|
||||||
|
|
||||||
>>> input = {'action': 'remove', 'qualifier': 'children',
|
>>> input = {'action': 'remove', 'qualifier': 'children',
|
||||||
... 'form.button.submit': 'Remove Chiildren',
|
... 'form.button.submit': 'Remove Chiildren',
|
||||||
|
@ -175,18 +175,18 @@ underlying context object:
|
||||||
>>> view.update()
|
>>> view.update()
|
||||||
True
|
True
|
||||||
>>> sorted(c.title for c in cc1.getChildren())
|
>>> sorted(c.title for c in cc1.getChildren())
|
||||||
['loops for Zope 3']
|
[u'loops for Zope 3']
|
||||||
|
|
||||||
We can also create a new concept and assign it.
|
We can also create a new concept and assign it.
|
||||||
|
|
||||||
>>> params = {'action': 'create', 'create.name': 'cc4',
|
>>> params = {'action': 'create', 'create.name': 'cc4',
|
||||||
... 'create.title': 'New concept',
|
... 'create.title': u'New concept',
|
||||||
... 'create.type': '.loops/concepts/topic'}
|
... 'create.type': '.loops/concepts/topic'}
|
||||||
>>> view = ConceptConfigureView(cc1, TestRequest(**params))
|
>>> view = ConceptConfigureView(cc1, TestRequest(**params))
|
||||||
>>> view.update()
|
>>> view.update()
|
||||||
True
|
True
|
||||||
>>> sorted(c.title for c in cc1.getChildren())
|
>>> sorted(c.title for c in cc1.getChildren())
|
||||||
['New concept', 'loops for Zope 3']
|
[u'New concept', u'loops for Zope 3']
|
||||||
|
|
||||||
The concept configuration view provides methods for displaying concept
|
The concept configuration view provides methods for displaying concept
|
||||||
types and predicates.
|
types and predicates.
|
||||||
|
@ -198,15 +198,15 @@ types and predicates.
|
||||||
>>> component.provideAdapter(LoopsTerms, (IIterableSource, IBrowserRequest), ITerms)
|
>>> component.provideAdapter(LoopsTerms, (IIterableSource, IBrowserRequest), ITerms)
|
||||||
|
|
||||||
>>> sorted((t.title, t.token) for t in view.conceptTypes())
|
>>> sorted((t.title, t.token) for t in view.conceptTypes())
|
||||||
[('Customer', '.loops/concepts/customer'),
|
[(u'Customer', '.loops/concepts/customer'),
|
||||||
('Domain', '.loops/concepts/domain'),
|
(u'Domain', '.loops/concepts/domain'),
|
||||||
('Predicate', '.loops/concepts/predicate'),
|
(u'Predicate', '.loops/concepts/predicate'),
|
||||||
('Topic', '.loops/concepts/topic'),
|
(u'Topic', '.loops/concepts/topic'),
|
||||||
('Type', '.loops/concepts/type'),
|
(u'Type', '.loops/concepts/type'),
|
||||||
('Unknown Type', '.loops/concepts/unknown')]
|
(u'Unknown Type', '.loops/concepts/unknown')]
|
||||||
|
|
||||||
>>> sorted((t.title, t.token) for t in view.predicates())
|
>>> sorted((t.title, t.token) for t in view.predicates())
|
||||||
[('subobject', '.loops/concepts/standard')]
|
[(u'subobject', '.loops/concepts/standard')]
|
||||||
|
|
||||||
Index attributes adapter
|
Index attributes adapter
|
||||||
------------------------
|
------------------------
|
||||||
|
@ -214,10 +214,10 @@ Index attributes adapter
|
||||||
>>> from loops.concept import IndexAttributes
|
>>> from loops.concept import IndexAttributes
|
||||||
>>> idx = IndexAttributes(cc2)
|
>>> idx = IndexAttributes(cc2)
|
||||||
>>> idx.text()
|
>>> idx.text()
|
||||||
'cc2 Zope 3'
|
u'cc2 Zope 3'
|
||||||
|
|
||||||
>>> idx.title()
|
>>> idx.title()
|
||||||
'cc2 Zope 3'
|
u'cc2 Zope 3'
|
||||||
|
|
||||||
|
|
||||||
Resources and what they have to do with Concepts
|
Resources and what they have to do with Concepts
|
||||||
|
@ -233,27 +233,27 @@ A common type of resource is a document:
|
||||||
|
|
||||||
>>> from loops.interfaces import IDocument
|
>>> from loops.interfaces import IDocument
|
||||||
>>> from loops.resource import Document
|
>>> from loops.resource import Document
|
||||||
>>> doc1 = Document('Zope Info')
|
>>> doc1 = Document(u'Zope Info')
|
||||||
>>> resources['doc1'] = doc1
|
>>> resources['doc1'] = doc1
|
||||||
>>> doc1.title
|
>>> doc1.title
|
||||||
'Zope Info'
|
u'Zope Info'
|
||||||
>>> doc1.data
|
>>> doc1.data
|
||||||
''
|
u''
|
||||||
>>> doc1.contentType
|
>>> doc1.contentType
|
||||||
''
|
u''
|
||||||
|
|
||||||
We can also directly use Resource objects; these behave like files.
|
We can also directly use Resource objects; these behave like files.
|
||||||
In fact, by using resource types we can explicitly assign a resource
|
In fact, by using resource types we can explicitly assign a resource
|
||||||
the 'file' type, but we will use this feature later:
|
the 'file' type, but we will use this feature later:
|
||||||
|
|
||||||
>>> img = Resource('A png Image')
|
>>> img = Resource(u'A png Image')
|
||||||
|
|
||||||
For testing we use some simple files from the tests directory:
|
For testing we use some simple files from the tests directory:
|
||||||
|
|
||||||
>>> from loops import tests
|
>>> from loops import tests
|
||||||
>>> import os
|
>>> import os
|
||||||
>>> path = os.path.join(*tests.__path__)
|
>>> path = os.path.join(*tests.__path__)
|
||||||
>>> img.data = open(os.path.join(path, 'test_icon.png'), 'rb').read()
|
>>> img.data = open(os.path.join(path, 'test_icon.png')).read()
|
||||||
>>> img.getSize()
|
>>> img.getSize()
|
||||||
381
|
381
|
||||||
>>> img.getImageSize()
|
>>> img.getImageSize()
|
||||||
|
@ -261,8 +261,8 @@ For testing we use some simple files from the tests directory:
|
||||||
>>> img.contentType
|
>>> img.contentType
|
||||||
'image/png'
|
'image/png'
|
||||||
|
|
||||||
>>> pdf = Resource('A pdf File')
|
>>> pdf = Resource(u'A pdf File')
|
||||||
>>> pdf.data = open(os.path.join(path, 'test.pdf'), 'rb').read()
|
>>> pdf.data = open(os.path.join(path, 'test.pdf')).read()
|
||||||
>>> pdf.getSize()
|
>>> pdf.getSize()
|
||||||
25862
|
25862
|
||||||
>>> pdf.getImageSize()
|
>>> pdf.getImageSize()
|
||||||
|
@ -287,7 +287,7 @@ from concepts to resources:
|
||||||
... 'tokens': ['.loops/resources/doc1:.loops/concepts/standard']}
|
... 'tokens': ['.loops/resources/doc1:.loops/concepts/standard']}
|
||||||
>>> view = ConceptConfigureView(cc1, TestRequest(form=form))
|
>>> view = ConceptConfigureView(cc1, TestRequest(form=form))
|
||||||
>>> [getName(r.context) for r in view.resources()]
|
>>> [getName(r.context) for r in view.resources()]
|
||||||
['doc1']
|
[u'doc1']
|
||||||
>>> view.update()
|
>>> view.update()
|
||||||
True
|
True
|
||||||
>>> len(cc1.getResources())
|
>>> len(cc1.getResources())
|
||||||
|
@ -316,10 +316,10 @@ Index attributes adapter
|
||||||
>>> component.provideAdapter(FileAdapter, provides=IFile)
|
>>> component.provideAdapter(FileAdapter, provides=IFile)
|
||||||
>>> idx = IndexAttributes(doc1)
|
>>> idx = IndexAttributes(doc1)
|
||||||
>>> idx.text()
|
>>> idx.text()
|
||||||
''
|
u''
|
||||||
|
|
||||||
>>> idx.title()
|
>>> idx.title()
|
||||||
'doc1 Zope Info'
|
u'doc1 Zope Info'
|
||||||
|
|
||||||
|
|
||||||
Views/Nodes: Menus, Menu Items, Listings, Pages, etc
|
Views/Nodes: Menus, Menu Items, Listings, Pages, etc
|
||||||
|
@ -343,14 +343,14 @@ The view manager has already been created during setup.
|
||||||
The view space is typically built up with nodes; a node may be a top-level
|
The view space is typically built up with nodes; a node may be a top-level
|
||||||
menu that may contain other nodes as menu or content items:
|
menu that may contain other nodes as menu or content items:
|
||||||
|
|
||||||
>>> m1 = views['m1'] = Node('Menu')
|
>>> m1 = views['m1'] = Node(u'Menu')
|
||||||
>>> m11 = m1['m11'] = Node('Zope')
|
>>> m11 = m1['m11'] = Node(u'Zope')
|
||||||
>>> m111 = m11['m111'] = Node('Zope in General')
|
>>> m111 = m11['m111'] = Node(u'Zope in General')
|
||||||
>>> m112 = m11['m112'] = Node('Zope 3')
|
>>> m112 = m11['m112'] = Node(u'Zope 3')
|
||||||
>>> m112.title
|
>>> m112.title
|
||||||
'Zope 3'
|
u'Zope 3'
|
||||||
>>> m112.description
|
>>> m112.description
|
||||||
''
|
u''
|
||||||
|
|
||||||
There are a few convienence methods for accessing parent and child nodes:
|
There are a few convienence methods for accessing parent and child nodes:
|
||||||
|
|
||||||
|
@ -359,7 +359,7 @@ There are a few convienence methods for accessing parent and child nodes:
|
||||||
>>> m11.getParentNode() is m1
|
>>> m11.getParentNode() is m1
|
||||||
True
|
True
|
||||||
>>> [getName(child) for child in m11.getChildNodes()]
|
>>> [getName(child) for child in m11.getChildNodes()]
|
||||||
['m111', 'm112']
|
[u'm111', u'm112']
|
||||||
|
|
||||||
What is returned by these may be controlled by the nodeType attribute:
|
What is returned by these may be controlled by the nodeType attribute:
|
||||||
|
|
||||||
|
@ -444,13 +444,13 @@ Node Views
|
||||||
>>> page = view.page
|
>>> page = view.page
|
||||||
>>> items = page.textItems
|
>>> items = page.textItems
|
||||||
>>> for item in items:
|
>>> for item in items:
|
||||||
... print(item.url, item.editable)
|
... print item.url, item.editable
|
||||||
http://127.0.0.1/loops/views/m1/m11/m112 False
|
http://127.0.0.1/loops/views/m1/m11/m112 False
|
||||||
|
|
||||||
>>> menu = view.menu
|
>>> menu = view.menu
|
||||||
>>> items = menu.menuItems
|
>>> items = menu.menuItems
|
||||||
>>> for item in items:
|
>>> for item in items:
|
||||||
... print(item.url, view.selected(item))
|
... print item.url, view.selected(item)
|
||||||
http://127.0.0.1/loops/views/m1/m11 True
|
http://127.0.0.1/loops/views/m1/m11 True
|
||||||
|
|
||||||
A NodeView provides an itemNum attribute that may be used to count elements
|
A NodeView provides an itemNum attribute that may be used to count elements
|
||||||
|
@ -493,11 +493,11 @@ view; these views we have to provide as multi-adapters:
|
||||||
>>> len(tt)
|
>>> len(tt)
|
||||||
9
|
9
|
||||||
>>> sorted((t.token, t.title) for t in view.targetTypes())[1]
|
>>> sorted((t.token, t.title) for t in view.targetTypes())[1]
|
||||||
('.loops/concepts/domain', 'Domain')
|
('.loops/concepts/domain', u'Domain')
|
||||||
>>> view.update()
|
>>> view.update()
|
||||||
True
|
True
|
||||||
>>> sorted(resources.keys())
|
>>> sorted(resources.keys())
|
||||||
['d001.txt', 'd002.txt', 'd003.txt', 'doc1', 'm1.m11.m111']
|
[u'd001.txt', u'd002.txt', u'd003.txt', u'doc1', u'm1.m11.m111']
|
||||||
|
|
||||||
>>> view.target.title, view.target.token
|
>>> view.target.title, view.target.token
|
||||||
('New Resource', '.loops/resources/m1.m11.m111')
|
('New Resource', '.loops/resources/m1.m11.m111')
|
||||||
|
@ -537,28 +537,28 @@ view for rendering.)
|
||||||
>>> component.provideAdapter(LoopsType)
|
>>> component.provideAdapter(LoopsType)
|
||||||
>>> view = NodeView(m112, TestRequest())
|
>>> view = NodeView(m112, TestRequest())
|
||||||
>>> view.renderTarget()
|
>>> view.renderTarget()
|
||||||
'<pre></pre>'
|
u'<pre></pre>'
|
||||||
>>> doc1.data = 'Test data\n\nAnother paragraph'
|
>>> doc1.data = u'Test data\n\nAnother paragraph'
|
||||||
>>> view.renderTarget()
|
>>> view.renderTarget()
|
||||||
'<pre>Test data\n\nAnother paragraph</pre>'
|
u'<pre>Test data\n\nAnother paragraph</pre>'
|
||||||
|
|
||||||
>>> doc1.contentType = 'text/restructured'
|
>>> doc1.contentType = 'text/restructured'
|
||||||
>>> doc1.data = 'Test data\n\nAnother `paragraph <para>`_'
|
>>> doc1.data = u'Test data\n\nAnother `paragraph <para>`_'
|
||||||
|
|
||||||
>>> from loops.wiki.base import wikiLinksActive
|
>>> from loops.wiki.base import wikiLinksActive
|
||||||
>>> wikiLinksActive(loopsRoot)
|
>>> wikiLinksActive(loopsRoot)
|
||||||
False
|
False
|
||||||
|
|
||||||
>>> view.renderTarget()
|
>>> view.renderTarget()
|
||||||
'<p>Test data</p>\n<p>Another <a class="reference external" href="para">paragraph</a></p>\n'
|
u'<p>Test data</p>\n<p>Another <a class="reference" href="para">paragraph</a></p>\n'
|
||||||
|
|
||||||
'<p>Test data</p>\n<p>Another <a class="reference create"
|
u'<p>Test data</p>\n<p>Another <a class="reference create"
|
||||||
href="http://127.0.0.1/loops/wiki/create.html?linkid=0000001">?paragraph</a></p>\n'
|
href="http://127.0.0.1/loops/wiki/create.html?linkid=0000001">?paragraph</a></p>\n'
|
||||||
|
|
||||||
>>> #links = loopsRoot.getRecordManager()['links']
|
>>> #links = loopsRoot.getRecordManager()['links']
|
||||||
>>> #links['0000001']
|
>>> #links['0000001']
|
||||||
|
|
||||||
<Link ['42', 1, '', '... ...', 'para', None]: {}>
|
<Link ['42', 1, '', '... ...', u'para', None]: {}>
|
||||||
|
|
||||||
If the target object is removed from its container all references
|
If the target object is removed from its container all references
|
||||||
to it are removed as well. (To make this work we have to handle
|
to it are removed as well. (To make this work we have to handle
|
||||||
|
@ -661,9 +661,9 @@ Breadcrumbs
|
||||||
>>> view = NodeView(m114, request)
|
>>> view = NodeView(m114, request)
|
||||||
>>> request.annotations.setdefault('loops.view', {})['nodeView'] = view
|
>>> request.annotations.setdefault('loops.view', {})['nodeView'] = view
|
||||||
>>> view.breadcrumbs()
|
>>> view.breadcrumbs()
|
||||||
[{'label': 'Menu', 'url': 'http://127.0.0.1/loops/views/m1'},
|
[{'url': 'http://127.0.0.1/loops/views/m1', 'label': u'Menu'},
|
||||||
{'label': 'Zope', 'url': 'http://127.0.0.1/loops/views/m1/m11'},
|
{'url': 'http://127.0.0.1/loops/views/m1/m11', 'label': u'Zope'},
|
||||||
{'label': '', 'url': 'http://127.0.0.1/loops/views/m1/m11/m114'}]
|
{'url': 'http://127.0.0.1/loops/views/m1/m11/m114', 'label': u''}]
|
||||||
|
|
||||||
|
|
||||||
End-user Forms and Special Views
|
End-user Forms and Special Views
|
||||||
|
@ -705,8 +705,8 @@ been created during setup.
|
||||||
>>> custType = TypeConcept(customer)
|
>>> custType = TypeConcept(customer)
|
||||||
>>> custType.options
|
>>> custType.options
|
||||||
[]
|
[]
|
||||||
>>> cust1 = concepts['cust1'] = Concept('Zope Corporation')
|
>>> cust1 = concepts['cust1'] = Concept(u'Zope Corporation')
|
||||||
>>> cust2 = concepts['cust2'] = Concept('cyberconcepts')
|
>>> cust2 = concepts['cust2'] = Concept(u'cyberconcepts')
|
||||||
>>> for c in (cust1, cust2): c.conceptType = customer
|
>>> for c in (cust1, cust2): c.conceptType = customer
|
||||||
>>> custType.options = ('qualifier:assign',)
|
>>> custType.options = ('qualifier:assign',)
|
||||||
>>> ConceptType(cust1).qualifiers
|
>>> ConceptType(cust1).qualifiers
|
||||||
|
@ -714,7 +714,7 @@ been created during setup.
|
||||||
|
|
||||||
>>> form = CreateObjectForm(m112, TestRequest())
|
>>> form = CreateObjectForm(m112, TestRequest())
|
||||||
>>> form.presetTypesForAssignment
|
>>> form.presetTypesForAssignment
|
||||||
[{'title': 'Customer', 'token': 'loops:concept:customer'}]
|
[{'token': 'loops:concept:customer', 'title': u'Customer'}]
|
||||||
|
|
||||||
If the node's target is a type concept we don't get any assignments because
|
If the node's target is a type concept we don't get any assignments because
|
||||||
it does not make much sense to assign resources or other concepts as
|
it does not make much sense to assign resources or other concepts as
|
||||||
|
@ -736,18 +736,18 @@ on data provided in this form:
|
||||||
>>> note_tc = concepts['note']
|
>>> note_tc = concepts['note']
|
||||||
|
|
||||||
>>> component.provideAdapter(NameChooser)
|
>>> component.provideAdapter(NameChooser)
|
||||||
>>> request = TestRequest(form={'title': 'Test Note',
|
>>> request = TestRequest(form={'title': u'Test Note',
|
||||||
... 'form.type': '.loops/concepts/note',
|
... 'form.type': u'.loops/concepts/note',
|
||||||
... 'contentType': 'text/restructured',
|
... 'contentType': u'text/restructured',
|
||||||
... 'linkUrl': 'http://'})
|
... 'linkUrl': u'http://'})
|
||||||
>>> view = NodeView(m112, request)
|
>>> view = NodeView(m112, request)
|
||||||
>>> cont = CreateObject(view, request)
|
>>> cont = CreateObject(view, request)
|
||||||
>>> cont.update()
|
>>> cont.update()
|
||||||
False
|
False
|
||||||
>>> sorted(resources.keys())
|
>>> sorted(resources.keys())
|
||||||
[...'test_note'...]
|
[...u'test_note'...]
|
||||||
>>> resources['test_note'].title
|
>>> resources['test_note'].title
|
||||||
'Test Note'
|
u'Test Note'
|
||||||
|
|
||||||
If there is a concept selected in the combo box we assign this to the newly
|
If there is a concept selected in the combo box we assign this to the newly
|
||||||
created object:
|
created object:
|
||||||
|
@ -755,8 +755,8 @@ created object:
|
||||||
>>> from loops import util
|
>>> from loops import util
|
||||||
>>> topicUid = util.getUidForObject(topic)
|
>>> topicUid = util.getUidForObject(topic)
|
||||||
>>> predicateUid = util.getUidForObject(concepts.getDefaultPredicate())
|
>>> predicateUid = util.getUidForObject(concepts.getDefaultPredicate())
|
||||||
>>> request = TestRequest(form={'title': 'Test Note',
|
>>> request = TestRequest(form={'title': u'Test Note',
|
||||||
... 'form.type': '.loops/concepts/note',
|
... 'form.type': u'.loops/concepts/note',
|
||||||
... 'form.assignments.selected':
|
... 'form.assignments.selected':
|
||||||
... [':'.join((topicUid, predicateUid))]})
|
... [':'.join((topicUid, predicateUid))]})
|
||||||
>>> view = NodeView(m112, request)
|
>>> view = NodeView(m112, request)
|
||||||
|
@ -764,22 +764,22 @@ created object:
|
||||||
>>> cont.update()
|
>>> cont.update()
|
||||||
False
|
False
|
||||||
>>> sorted(resources.keys())
|
>>> sorted(resources.keys())
|
||||||
[...'test_note-2'...]
|
[...u'test_note-2'...]
|
||||||
>>> note = resources['test_note-2']
|
>>> note = resources['test_note-2']
|
||||||
>>> sorted(t.__name__ for t in note.getConcepts())
|
>>> sorted(t.__name__ for t in note.getConcepts())
|
||||||
['note', 'topic']
|
[u'note', u'topic']
|
||||||
|
|
||||||
When creating an object its name may be automatically generated using the title
|
When creating an object its name may be automatically generated using the title
|
||||||
of the object. Let's make sure that the name chooser also handles special
|
of the object. Let's make sure that the name chooser also handles special
|
||||||
and possibly critcal cases:
|
and possibly critcal cases:
|
||||||
|
|
||||||
>>> nc = NameChooser(resources)
|
>>> nc = NameChooser(resources)
|
||||||
>>> nc.chooseName('', Resource('abc: (cde)'))
|
>>> nc.chooseName(u'', Resource(u'abc: (cde)'))
|
||||||
'abc__cde'
|
u'abc__cde'
|
||||||
>>> nc.chooseName('', Resource('\xdcml\xe4ut'))
|
>>> nc.chooseName(u'', Resource(u'\xdcml\xe4ut'))
|
||||||
'uemlaeut'
|
u'uemlaeut'
|
||||||
>>> nc.chooseName('', Resource('A very very loooooong title'))
|
>>> nc.chooseName(u'', Resource(u'A very very loooooong title'))
|
||||||
'a_title'
|
u'a_title'
|
||||||
|
|
||||||
Editing an Object
|
Editing an Object
|
||||||
-----------------
|
-----------------
|
||||||
|
@ -796,7 +796,7 @@ that in turns calls formlibs ``setUpWidgets()``.
|
||||||
The new technique uses the ``fields`` and ``data`` attributes...
|
The new technique uses the ``fields`` and ``data`` attributes...
|
||||||
|
|
||||||
>>> for f in view.fields:
|
>>> for f in view.fields:
|
||||||
... print(f.name, f.fieldType, f.required, f.vocabulary)
|
... print f.name, f.fieldType, f.required, f.vocabulary
|
||||||
title textline True None
|
title textline True None
|
||||||
data textarea False None
|
data textarea False None
|
||||||
contentType dropdown True <...SimpleVocabulary object...>
|
contentType dropdown True <...SimpleVocabulary object...>
|
||||||
|
@ -804,22 +804,22 @@ The new technique uses the ``fields`` and ``data`` attributes...
|
||||||
linkText textline False None
|
linkText textline False None
|
||||||
|
|
||||||
>>> view.data
|
>>> view.data
|
||||||
{'title': 'Test Note', 'data': '', 'contentType': 'text/restructured',
|
{'linkUrl': u'http://', 'contentType': u'text/restructured', 'data': u'',
|
||||||
'linkUrl': 'http://', 'linkText': ''}
|
'linkText': u'', 'title': u'Test Note'}
|
||||||
|
|
||||||
The object is changed via a FormController adapter created for
|
The object is changed via a FormController adapter created for
|
||||||
a NodeView.
|
a NodeView.
|
||||||
|
|
||||||
>>> form = dict(
|
>>> form = dict(
|
||||||
... title='Test Note - changed',
|
... title=u'Test Note - changed',
|
||||||
... contentType='text/plain',)
|
... contentType=u'text/plain',)
|
||||||
>>> request = TestRequest(form=form)
|
>>> request = TestRequest(form=form)
|
||||||
>>> view = NodeView(m112, request)
|
>>> view = NodeView(m112, request)
|
||||||
>>> cont = EditObject(view, request)
|
>>> cont = EditObject(view, request)
|
||||||
>>> cont.update()
|
>>> cont.update()
|
||||||
False
|
False
|
||||||
>>> resources['test_note'].title
|
>>> resources['test_note'].title
|
||||||
'Test Note - changed'
|
u'Test Note - changed'
|
||||||
|
|
||||||
Virtual Targets
|
Virtual Targets
|
||||||
---------------
|
---------------
|
||||||
|
@ -883,13 +883,13 @@ informations about all parents of an object.
|
||||||
|
|
||||||
>>> parents = m113.getAllParents()
|
>>> parents = m113.getAllParents()
|
||||||
>>> for p in parents:
|
>>> for p in parents:
|
||||||
... print(p.object.title)
|
... print p.object.title
|
||||||
Zope
|
Zope
|
||||||
Menu
|
Menu
|
||||||
|
|
||||||
>>> parents = resources['test_note'].getAllParents()
|
>>> parents = resources['test_note'].getAllParents()
|
||||||
>>> for p in parents:
|
>>> for p in parents:
|
||||||
... print(p.object.title, len(p.relations))
|
... print p.object.title, len(p.relations)
|
||||||
Note 1
|
Note 1
|
||||||
Type 2
|
Type 2
|
||||||
|
|
||||||
|
@ -916,30 +916,10 @@ relates ISO country codes with the full name of the country.
|
||||||
[('at', ['Austria']), ('de', ['Germany'])]
|
[('at', ['Austria']), ('de', ['Germany'])]
|
||||||
|
|
||||||
>>> countries.dataAsRecords()
|
>>> countries.dataAsRecords()
|
||||||
[{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}]
|
[{'value': 'Austria', 'key': 'at'}, {'value': 'Germany', 'key': 'de'}]
|
||||||
|
|
||||||
>>> countries.getRowsByValue('value', 'Germany')
|
>>> countries.getRowsByValue('value', 'Germany')
|
||||||
[{'key': 'de', 'value': 'Germany'}]
|
[{'value': 'Germany', 'key': 'de'}]
|
||||||
|
|
||||||
The ``recordstable`` type is a variation of this datable type that contains
|
|
||||||
a simple list of records - without a key column. A record in this type is a
|
|
||||||
dictionary with the field name as key and the field value as value.
|
|
||||||
|
|
||||||
>>> from loops.table import IRecordsTable, RecordsTable
|
|
||||||
>>> component.provideAdapter(RecordsTable, provides=IRecordsTable)
|
|
||||||
|
|
||||||
>>> drType = addAndConfigureObject(concepts, Concept, 'recordstable',
|
|
||||||
... title='Records Table', conceptType=concepts['type'],
|
|
||||||
... typeInterface=IRecordsTable)
|
|
||||||
|
|
||||||
We just reuse the existing ``countries`` table and convert it to a records table.
|
|
||||||
|
|
||||||
>>> baseObject(countries).setType(drType)
|
|
||||||
|
|
||||||
>>> countries = adapted(concepts['countries'])
|
|
||||||
|
|
||||||
>>> countries.data
|
|
||||||
[{'key': 'at', 'value': 'Austria'}, {'key': 'de', 'value': 'Germany'}]
|
|
||||||
|
|
||||||
|
|
||||||
Caching
|
Caching
|
||||||
|
@ -951,7 +931,7 @@ To be done...
|
||||||
>>> obj = resources['test_note']
|
>>> obj = resources['test_note']
|
||||||
>>> cxObj = cached(obj)
|
>>> cxObj = cached(obj)
|
||||||
>>> [p.object.title for p in cxObj.getAllParents()]
|
>>> [p.object.title for p in cxObj.getAllParents()]
|
||||||
['Note', 'Type']
|
[u'Note', u'Type']
|
||||||
|
|
||||||
|
|
||||||
Security
|
Security
|
||||||
|
@ -960,12 +940,6 @@ Security
|
||||||
>>> from loops.security.browser import admin, audit
|
>>> from loops.security.browser import admin, audit
|
||||||
|
|
||||||
|
|
||||||
Paster Shell Utilities - Repair Scripts
|
|
||||||
=======================================
|
|
||||||
|
|
||||||
>>> from loops.repair.base import removeRecords
|
|
||||||
|
|
||||||
|
|
||||||
Import/Export
|
Import/Export
|
||||||
=============
|
=============
|
||||||
|
|
22
__init__.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
$Id$
|
||||||
|
"""
|
|
@ -1,13 +1,33 @@
|
||||||
# loops.base
|
# -*- coding: UTF-8 -*-
|
||||||
|
# -*- Mode: Python; py-indent-offset: 4 -*-
|
||||||
|
#
|
||||||
|
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Implementation of loops root object.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.container.btree import BTreeContainer
|
$Id$
|
||||||
from zope.site.folder import Folder
|
"""
|
||||||
from zope.site.interfaces import IFolder
|
|
||||||
|
from zope.app.container.btree import BTreeContainer
|
||||||
|
from zope.app.folder.folder import Folder
|
||||||
|
from zope.app.folder.interfaces import IFolder
|
||||||
from zope.traversing.api import getPath, traverse
|
from zope.traversing.api import getPath, traverse
|
||||||
from zope.interface import implementer
|
from zope.interface import implements
|
||||||
|
|
||||||
from cybertools.util.jeep import Jeep
|
from cybertools.util.jeep import Jeep
|
||||||
from loops.interfaces import ILoops
|
from loops.interfaces import ILoops
|
||||||
|
@ -15,8 +35,17 @@ from loops.interfaces import ILoops
|
||||||
loopsPrefix = '.loops'
|
loopsPrefix = '.loops'
|
||||||
|
|
||||||
|
|
||||||
@implementer(ILoops)
|
|
||||||
class Loops(Folder):
|
class Loops(Folder):
|
||||||
|
#class Loops(BTreeContainer):
|
||||||
|
|
||||||
|
implements(ILoops)
|
||||||
|
|
||||||
|
#def getSiteManager(self):
|
||||||
|
# return self.__parent__.getSiteManager()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def _SampleContainer__data(self):
|
||||||
|
return self.data
|
||||||
|
|
||||||
_skinName = ''
|
_skinName = ''
|
||||||
def getSkinName(self): return self._skinName
|
def getSkinName(self): return self._skinName
|
||||||
|
@ -46,8 +75,7 @@ class Loops(Folder):
|
||||||
return self.get('records')
|
return self.get('records')
|
||||||
|
|
||||||
def getLoopsUri(self, obj):
|
def getLoopsUri(self, obj):
|
||||||
uri = loopsPrefix + getPath(obj)[len(getPath(self)):]
|
return str(loopsPrefix + getPath(obj)[len(getPath(self)):])
|
||||||
return uri
|
|
||||||
|
|
||||||
def loopsTraverse(self, uri):
|
def loopsTraverse(self, uri):
|
||||||
prefix = loopsPrefix + '/'
|
prefix = loopsPrefix + '/'
|
|
@ -1,9 +1,26 @@
|
||||||
# loops.browser.action
|
#
|
||||||
|
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Base classes (sort of views) for action portlet items.
|
"""
|
||||||
|
Base classes (sort of views) for action portlet items.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from urllib.parse import urlencode
|
from urllib import urlencode
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
@ -108,15 +125,6 @@ actions.register('external_edit', 'object', TargetAction,
|
||||||
cssClass='icon-action',
|
cssClass='icon-action',
|
||||||
)
|
)
|
||||||
|
|
||||||
actions.register('create_object', 'portlet', DialogAction,
|
|
||||||
title=_('Create Resource...'),
|
|
||||||
description=_('Create a new resource object.'),
|
|
||||||
viewName='create_object.html',
|
|
||||||
dialogName='edit',
|
|
||||||
prerequisites=['registerDojoEditor'],
|
|
||||||
permission='zope.ManageContent',
|
|
||||||
)
|
|
||||||
|
|
||||||
actions.register('edit_object', 'portlet', DialogAction,
|
actions.register('edit_object', 'portlet', DialogAction,
|
||||||
title=_(u'Edit Resource...'),
|
title=_(u'Edit Resource...'),
|
||||||
description=_(u'Modify resource object.'),
|
description=_(u'Modify resource object.'),
|
61
browser/auth.py
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
|
from zope.app.security.interfaces import IAuthentication
|
||||||
|
from zope.app.security.interfaces import ILogout, IUnauthenticatedPrincipal
|
||||||
|
from zope import component
|
||||||
|
from zope.interface import implements
|
||||||
|
|
||||||
|
from loops.browser.node import NodeView
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
|
||||||
|
|
||||||
|
class LoginForm(NodeView):
|
||||||
|
|
||||||
|
template = ViewPageTemplateFile('auth.pt')
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def macro(self):
|
||||||
|
return self.template.macros['login_form']
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def item(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
class Logout(object):
|
||||||
|
|
||||||
|
implements(ILogout)
|
||||||
|
|
||||||
|
def __init__(self, context, request):
|
||||||
|
self.context = context
|
||||||
|
self.request = request
|
||||||
|
|
||||||
|
def __call__(self):
|
||||||
|
nextUrl = self.request.get('nextURL') or self.request.URL[-1]
|
||||||
|
if not IUnauthenticatedPrincipal.providedBy(self.request.principal):
|
||||||
|
auth = component.getUtility(IAuthentication)
|
||||||
|
ILogout(auth).logout(self.request)
|
||||||
|
return self.request.response.redirect(nextUrl)
|
||||||
|
|
||||||
|
|
96
loops/browser/common.py → browser/common.py
Executable file → Normal file
|
@ -1,28 +1,45 @@
|
||||||
# loops.browser.common
|
#
|
||||||
|
# Copyright (c) 2015 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Common base class for loops browser view classes.
|
"""
|
||||||
|
Common base class for loops browser view classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from cgi import parse_qs, parse_qsl
|
||||||
#import mimetypes # use more specific assignments from cybertools.text
|
#import mimetypes # use more specific assignments from cybertools.text
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
from logging import getLogger
|
|
||||||
import re
|
import re
|
||||||
from time import strptime
|
from time import strptime
|
||||||
from urllib.parse import parse_qs, parse_qsl, urlencode
|
from urllib import urlencode
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.authentication.interfaces import IAuthentication, IUnauthenticatedPrincipal
|
from zope.app.form.browser.interfaces import ITerms
|
||||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
from zope.app.i18n.interfaces import ITranslationDomain
|
||||||
from zope.authentication.interfaces import PrincipalLookupError
|
from zope.app.security.interfaces import IAuthentication, IUnauthenticatedPrincipal
|
||||||
from zope.browser.interfaces import ITerms
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
|
from zope.app.security.interfaces import PrincipalLookupError
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.dublincore.interfaces import IZopeDublinCore
|
from zope.dublincore.interfaces import IZopeDublinCore
|
||||||
from zope.formlib import form
|
from zope.formlib import form
|
||||||
from zope.formlib.form import FormFields
|
from zope.formlib.form import FormFields
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
from zope.i18n.interfaces import ITranslationDomain
|
from zope.interface import Interface, implements
|
||||||
from zope.interface import Interface, implementer
|
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.publisher.browser import applySkin
|
from zope.publisher.browser import applySkin
|
||||||
from zope.publisher.interfaces.browser import IBrowserSkinType, IBrowserView
|
from zope.publisher.interfaces.browser import IBrowserSkinType, IBrowserView
|
||||||
|
@ -81,20 +98,16 @@ class NameField(schema.ASCIILine):
|
||||||
class ViewMode(object):
|
class ViewMode(object):
|
||||||
|
|
||||||
def __init__(self, name='view', title=None, url=None, active=False,
|
def __init__(self, name='view', title=None, url=None, active=False,
|
||||||
description=u'', subViewModes=Jeep()):
|
description=u''):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.title = title
|
self.title = title
|
||||||
self.url = url
|
self.url = url
|
||||||
self.active = active
|
self.active = active
|
||||||
self.description = description
|
self.description = description
|
||||||
self.subViewModes = subViewModes
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cssClass(self):
|
def cssClass(self):
|
||||||
result = self.active and u'active' or u'inactive'
|
return self.active and u'active' or u'inactive'
|
||||||
if self.subViewModes:
|
|
||||||
result += u' sub-modes'
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class IAddForm(Interface):
|
class IAddForm(Interface):
|
||||||
|
@ -179,11 +192,9 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
actions = {}
|
actions = {}
|
||||||
portlet_actions = []
|
portlet_actions = []
|
||||||
parts = ()
|
parts = ()
|
||||||
subparts = ()
|
|
||||||
icon = None
|
icon = None
|
||||||
modeName = 'view'
|
modeName = 'view'
|
||||||
isToplevel = False
|
isToplevel = False
|
||||||
isVisible = True
|
|
||||||
|
|
||||||
def __init__(self, context, request):
|
def __init__(self, context, request):
|
||||||
context = baseObject(context)
|
context = baseObject(context)
|
||||||
|
@ -192,10 +203,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
self.context = removeSecurityProxy(context)
|
self.context = removeSecurityProxy(context)
|
||||||
try:
|
try:
|
||||||
if not self.checkPermissions():
|
if not self.checkPermissions():
|
||||||
logger = getLogger('loops.browser.common-153')
|
|
||||||
principal = request.principal and request.principal.id
|
|
||||||
msg = 'Unauthorized: %s, %s' % (self.contextInfo, principal)
|
|
||||||
logger.warn(msg)
|
|
||||||
raise Unauthorized(str(self.contextInfo))
|
raise Unauthorized(str(self.contextInfo))
|
||||||
except ForbiddenAttribute: # ignore when testing
|
except ForbiddenAttribute: # ignore when testing
|
||||||
pass
|
pass
|
||||||
|
@ -208,11 +215,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
def checkPermissions(self):
|
def checkPermissions(self):
|
||||||
return canAccessObject(self.context)
|
return canAccessObject(self.context)
|
||||||
|
|
||||||
def translate(self, text, msgFactory=_):
|
|
||||||
if msgFactory is None:
|
|
||||||
return text
|
|
||||||
return msgFactory(text)
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def contextInfo(self):
|
def contextInfo(self):
|
||||||
return dict(view=self, context=getName(self.context))
|
return dict(view=self, context=getName(self.context))
|
||||||
|
@ -359,10 +361,7 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
for c in cr:
|
for c in cr:
|
||||||
try:
|
try:
|
||||||
principal = pau.getPrincipal(c)
|
principal = pau.getPrincipal(c)
|
||||||
if principal is None:
|
creators.append(principal.title)
|
||||||
creators.append(c)
|
|
||||||
else:
|
|
||||||
creators.append(principal.title)
|
|
||||||
except PrincipalLookupError:
|
except PrincipalLookupError:
|
||||||
creators.append(c)
|
creators.append(c)
|
||||||
return creators
|
return creators
|
||||||
|
@ -451,10 +450,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
def description(self):
|
def description(self):
|
||||||
return self.adapted.description
|
return self.adapted.description
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def tabTitle(self):
|
|
||||||
return u'Info'
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def additionalInfos(self):
|
def additionalInfos(self):
|
||||||
return []
|
return []
|
||||||
|
@ -679,11 +674,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
def typeOptions(self):
|
def typeOptions(self):
|
||||||
if self.typeProvider is None:
|
if self.typeProvider is None:
|
||||||
return DummyOptions()
|
return DummyOptions()
|
||||||
if getattr(self.adapted, '__is_dummy__', None):
|
|
||||||
typeToken = getattr(self, 'typeToken', None)
|
|
||||||
if typeToken is not None:
|
|
||||||
typeProvider = self.loopsRoot.loopsTraverse(typeToken)
|
|
||||||
return IOptions(adapted(typeProvider))
|
|
||||||
return IOptions(adapted(self.typeProvider))
|
return IOptions(adapted(self.typeProvider))
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -757,9 +747,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
if not self.useVersioning:
|
if not self.useVersioning:
|
||||||
return None
|
return None
|
||||||
target = self.target
|
target = self.target
|
||||||
if not IResource.providedBy(target):
|
|
||||||
# no standard versioning yet for concepts
|
|
||||||
return None
|
|
||||||
versionable = IVersionable(target, None)
|
versionable = IVersionable(target, None)
|
||||||
if versionable is None:
|
if versionable is None:
|
||||||
return ''
|
return ''
|
||||||
|
@ -874,8 +861,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
|
|
||||||
def checkAction(self, name, category, target):
|
def checkAction(self, name, category, target):
|
||||||
if name in ('create_resource',):
|
if name in ('create_resource',):
|
||||||
if target is not None and target.options.showCreateResource:
|
|
||||||
return True
|
|
||||||
return not self.globalOptions('hideCreateResource')
|
return not self.globalOptions('hideCreateResource')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -895,7 +880,6 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def xeditable(self):
|
def xeditable(self):
|
||||||
return False
|
|
||||||
if self.typeOptions('no_external_edit'):
|
if self.typeOptions('no_external_edit'):
|
||||||
return False
|
return False
|
||||||
ct = getattr(self.context, 'contentType', '')
|
ct = getattr(self.context, 'contentType', '')
|
||||||
|
@ -944,9 +928,9 @@ class BaseView(GenericView, I18NView, SortableMixin):
|
||||||
djConfig='parseOnLoad: true, usePlainJson: true, '
|
djConfig='parseOnLoad: true, usePlainJson: true, '
|
||||||
#'isDebug: true, '
|
#'isDebug: true, '
|
||||||
'locale: "%s"' % self.languageInfo.language)
|
'locale: "%s"' % self.languageInfo.language)
|
||||||
jsCall = ('dojo.require("dojo.parser"); ')
|
jsCall = ('dojo.require("dojo.parser"); '
|
||||||
#'dojo.registerModulePath("jocy", "/@@/cybertools.jocy"); '
|
'dojo.registerModulePath("jocy", "/@@/cybertools.jocy"); '
|
||||||
#'dojo.require("jocy.data");')
|
'dojo.require("jocy.data");')
|
||||||
cm.register('js-execute', 'dojo_registration', jsCall=jsCall)
|
cm.register('js-execute', 'dojo_registration', jsCall=jsCall)
|
||||||
cm.register('css', identifier='Lightbox.css', position=0,
|
cm.register('css', identifier='Lightbox.css', position=0,
|
||||||
resourceName='ajax.dojo/dojox/image/resources/Lightbox.css',
|
resourceName='ajax.dojo/dojox/image/resources/Lightbox.css',
|
||||||
|
@ -1074,32 +1058,33 @@ class LoggedIn(object):
|
||||||
|
|
||||||
# vocabulary stuff
|
# vocabulary stuff
|
||||||
|
|
||||||
@implementer(ITerms)
|
|
||||||
class SimpleTerms(object):
|
class SimpleTerms(object):
|
||||||
""" Provide the ITerms interface, e.g. for usage in selection
|
""" Provide the ITerms interface, e.g. for usage in selection
|
||||||
lists.
|
lists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
implements(ITerms)
|
||||||
|
|
||||||
def __init__(self, source, request):
|
def __init__(self, source, request):
|
||||||
# the source parameter is a list of tuples (token, title).
|
# the source parameter is a list of tuples (token, title).
|
||||||
self.source = source
|
self.source = source
|
||||||
self.terms = dict(source)
|
self.terms = dict(source)
|
||||||
|
|
||||||
def getTerm(self, value):
|
def getTerm(self, value):
|
||||||
token = value[0]
|
token, title = value
|
||||||
title = len(value) > 1 and value[1] or token
|
|
||||||
return SimpleTerm(token, token, title)
|
return SimpleTerm(token, token, title)
|
||||||
|
|
||||||
def getValue(self, token):
|
def getValue(self, token):
|
||||||
return (token, self.terms[token])
|
return (token, self.terms[token])
|
||||||
|
|
||||||
|
|
||||||
@implementer(ITerms)
|
|
||||||
class LoopsTerms(object):
|
class LoopsTerms(object):
|
||||||
""" Provide the ITerms interface, e.g. for usage in selection
|
""" Provide the ITerms interface, e.g. for usage in selection
|
||||||
lists.
|
lists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
implements(ITerms)
|
||||||
|
|
||||||
def __init__(self, source, request):
|
def __init__(self, source, request):
|
||||||
# the source parameter is a view or adapter of a real context object:
|
# the source parameter is a view or adapter of a real context object:
|
||||||
self.source = source
|
self.source = source
|
||||||
|
@ -1121,11 +1106,12 @@ class LoopsTerms(object):
|
||||||
return self.loopsRoot.loopsTraverse(token)
|
return self.loopsRoot.loopsTraverse(token)
|
||||||
|
|
||||||
|
|
||||||
@implementer(ITerms)
|
|
||||||
class InterfaceTerms(object):
|
class InterfaceTerms(object):
|
||||||
""" Provide the ITerms interface for source list of interfaces.
|
""" Provide the ITerms interface for source list of interfaces.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
implements(ITerms)
|
||||||
|
|
||||||
def __init__(self, source, request):
|
def __init__(self, source, request):
|
||||||
self.source = source
|
self.source = source
|
||||||
self.request = request
|
self.request = request
|
|
@ -1,22 +1,40 @@
|
||||||
# loops.browser.concept
|
#
|
||||||
|
# Copyright (c) 2013 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Definition of the concept view classes.
|
"""
|
||||||
|
Definition of the concept view classes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from zope import interface, component, schema
|
from zope import interface, component, schema
|
||||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.browser.interfaces import ITerms
|
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
from zope.app.container.contained import ObjectRemovedEvent
|
||||||
|
from zope.app.form.browser.interfaces import ITerms
|
||||||
|
from zope.app.form.interfaces import IDisplayWidget
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.catalog.interfaces import ICatalog
|
|
||||||
from zope.container.contained import ObjectRemovedEvent
|
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
from zope.formlib.form import EditForm, FormFields, setUpEditWidgets
|
from zope.formlib.form import EditForm, FormFields, setUpEditWidgets
|
||||||
from zope.formlib.interfaces import IDisplayWidget
|
|
||||||
from zope.formlib.namedtemplate import NamedTemplate
|
from zope.formlib.namedtemplate import NamedTemplate
|
||||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
from zope.interface import implements
|
||||||
from zope.publisher.interfaces import BadRequest
|
from zope.publisher.interfaces import BadRequest
|
||||||
from zope.publisher.interfaces.browser import IBrowserRequest
|
from zope.publisher.interfaces.browser import IBrowserRequest
|
||||||
from zope.schema.interfaces import IIterableSource
|
from zope.schema.interfaces import IIterableSource
|
||||||
|
@ -236,35 +254,18 @@ class ConceptView(BaseView):
|
||||||
result.append(view)
|
result.append(view)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def viewModes(self):
|
|
||||||
modes = Jeep()
|
|
||||||
current = self.request.form.get('loops.viewName')
|
|
||||||
parts = (self.options('view_tabs') or
|
|
||||||
self.typeOptions('view_tabs') or [])
|
|
||||||
if not parts:
|
|
||||||
return modes
|
|
||||||
activeMode = None
|
|
||||||
for p in parts:
|
|
||||||
view = component.queryMultiAdapter(
|
|
||||||
(self.adapted, self.request), name=p)
|
|
||||||
if view is None:
|
|
||||||
view = component.queryMultiAdapter(
|
|
||||||
(self.context, self.request), name=p)
|
|
||||||
if view is None:
|
|
||||||
continue
|
|
||||||
active = (activeMode is None and p == current)
|
|
||||||
if active:
|
|
||||||
activeMode = p
|
|
||||||
url = '%s?loops.viewName=%s' % (self.targetUrl, p)
|
|
||||||
modes.append(ViewMode(p, view.tabTitle, url, active))
|
|
||||||
if activeMode is None:
|
|
||||||
modes[0].active = True
|
|
||||||
return modes
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def adapted(self):
|
def adapted(self):
|
||||||
return adapted(self.context, self.languageInfo)
|
return adapted(self.context, self.languageInfo)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def title(self):
|
||||||
|
return self.adapted.title or getName(self.context)
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
def description(self):
|
||||||
|
return self.adapted.description
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def targetUrl(self):
|
def targetUrl(self):
|
||||||
return self.nodeView.getUrlForTarget(self.context)
|
return self.nodeView.getUrlForTarget(self.context)
|
||||||
|
@ -290,7 +291,7 @@ class ConceptView(BaseView):
|
||||||
def breadcrumbsParent(self):
|
def breadcrumbsParent(self):
|
||||||
for p in self.context.getParents([self.defaultPredicate]):
|
for p in self.context.getParents([self.defaultPredicate]):
|
||||||
view = self.nodeView.getViewForTarget(p)
|
view = self.nodeView.getViewForTarget(p)
|
||||||
if view is not None and view.showInBreadcrumbs:
|
if view.showInBreadcrumbs:
|
||||||
return view
|
return view
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -397,8 +398,7 @@ class ConceptView(BaseView):
|
||||||
children = getChildren
|
children = getChildren
|
||||||
|
|
||||||
def childrenAlphaGroups(self, predicates=None):
|
def childrenAlphaGroups(self, predicates=None):
|
||||||
#result = Jeep()
|
result = Jeep()
|
||||||
result = {}
|
|
||||||
rels = self.getChildren(predicates=predicates or [self.defaultPredicate],
|
rels = self.getChildren(predicates=predicates or [self.defaultPredicate],
|
||||||
topLevelOnly=False, sort=False)
|
topLevelOnly=False, sort=False)
|
||||||
rels = sorted(rels, key=lambda r: r.title.lower())
|
rels = sorted(rels, key=lambda r: r.title.lower())
|
||||||
|
@ -445,7 +445,7 @@ class ConceptView(BaseView):
|
||||||
|
|
||||||
def parents(self):
|
def parents(self):
|
||||||
rels = sorted(self.context.getParentRelations(),
|
rels = sorted(self.context.getParentRelations(),
|
||||||
key=(lambda x: x.first.title and x.first.title.lower() or ''))
|
key=(lambda x: x.first.title and x.first.title.lower()))
|
||||||
for r in rels:
|
for r in rels:
|
||||||
yield self.childViewFactory(r, self.request)
|
yield self.childViewFactory(r, self.request)
|
||||||
|
|
|
@ -10,9 +10,7 @@
|
||||||
|
|
||||||
<metal:data define-macro="conceptdata">
|
<metal:data define-macro="conceptdata">
|
||||||
<div tal:attributes="class string:content-$level;">
|
<div tal:attributes="class string:content-$level;">
|
||||||
<tal:block condition="not:title_shown|python:False">
|
<metal:block use-macro="view/concept_macros/concepttitle" />
|
||||||
<metal:block use-macro="view/concept_macros/concepttitle"/>
|
|
||||||
</tal:block>
|
|
||||||
<metal:slot define-slot="fields">
|
<metal:slot define-slot="fields">
|
||||||
<metal:block use-macro="view/concept_macros/conceptfields" />
|
<metal:block use-macro="view/concept_macros/conceptfields" />
|
||||||
</metal:slot>
|
</metal:slot>
|
||||||
|
@ -53,7 +51,7 @@
|
||||||
<h1 tal:define="tabview item/tabview|nothing"
|
<h1 tal:define="tabview item/tabview|nothing"
|
||||||
tal:attributes="ondblclick item/openEditWindow">
|
tal:attributes="ondblclick item/openEditWindow">
|
||||||
<a tal:omit-tag="python: level > 1"
|
<a tal:omit-tag="python: level > 1"
|
||||||
tal:attributes="href string:${view/requestUrl}${item/urlParamString}"
|
tal:attributes="href string:${request/URL}${item/urlParamString}"
|
||||||
tal:content="item/title">Title</a>
|
tal:content="item/title">Title</a>
|
||||||
<a title="Show tabular view"
|
<a title="Show tabular view"
|
||||||
i18n:attributes="title"
|
i18n:attributes="title"
|
||||||
|
@ -89,10 +87,9 @@
|
||||||
fieldInstance python:field.getFieldInstance(
|
fieldInstance python:field.getFieldInstance(
|
||||||
context=context, request=request);
|
context=context, request=request);
|
||||||
rendererName field/displayRenderer;
|
rendererName field/displayRenderer;
|
||||||
renderer python:
|
renderer python:fieldInstance.getRenderer(rendererName) or
|
||||||
fieldInstance.getRenderer(rendererName) or
|
view.concept_macros[rendererName]"
|
||||||
view.concept_macros[rendererName]"
|
tal:condition="nocall:value">
|
||||||
tal:condition="python:field.visible and (value or field.showEmpty)">
|
|
||||||
<td><b tal:content="field/title" i18n:translate="" />:</td>
|
<td><b tal:content="field/title" i18n:translate="" />:</td>
|
||||||
<td><span metal:use-macro="renderer" /></td>
|
<td><span metal:use-macro="renderer" /></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -118,6 +115,15 @@
|
||||||
</metal:email>
|
</metal:email>
|
||||||
|
|
||||||
|
|
||||||
|
<metal:email define-macro="display_relationset">
|
||||||
|
<span tal:repeat="elem value">
|
||||||
|
<a tal:attributes="href elem/url"
|
||||||
|
tal:content="elem/label"></a>
|
||||||
|
<tal:separator condition="not:repeat/elem/end"> | </tal:separator>
|
||||||
|
</span>
|
||||||
|
</metal:email>
|
||||||
|
|
||||||
|
|
||||||
<metal:parents define-macro="conceptparents">
|
<metal:parents define-macro="conceptparents">
|
||||||
<div tal:attributes="class string:content-$level;
|
<div tal:attributes="class string:content-$level;
|
||||||
ondblclick python: item.openEditWindow('configure.html')">
|
ondblclick python: item.openEditWindow('configure.html')">
|
||||||
|
@ -185,17 +191,14 @@
|
||||||
tal:attributes="value related/uidToken" />
|
tal:attributes="value related/uidToken" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tal:nested condition="list_nested">
|
<tr tal:define="children python:list(related.unique(related.children()));
|
||||||
<tr tal:define="children python:
|
resources python:list(related.resources())"
|
||||||
list(related.unique(related.children()));
|
tal:condition="python:list_nested and (children or resources)">
|
||||||
resources python:list(related.resources())"
|
<td tal:condition="item/showCheckboxes|nothing" />
|
||||||
tal:condition="python:children or resources">
|
<td colspan="5">
|
||||||
<td tal:condition="item/showCheckboxes|nothing" />
|
<metal:list use-macro="item/template/macros/list_nested" />
|
||||||
<td colspan="5">
|
</td>
|
||||||
<metal:list use-macro="item/template/macros/list_nested" />
|
</tr>
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</tal:nested>
|
|
||||||
</tal:item>
|
</tal:item>
|
||||||
</tal:items>
|
</tal:items>
|
||||||
</tbody>
|
</tbody>
|
|
@ -34,18 +34,16 @@
|
||||||
|
|
||||||
<!-- login/logout -->
|
<!-- login/logout -->
|
||||||
|
|
||||||
<!--<page for="loops.interfaces.INode"
|
<page for="loops.interfaces.INode"
|
||||||
name="login.html"
|
name="login.html"
|
||||||
class="loops.browser.auth.LoginForm"
|
class="loops.browser.auth.LoginForm"
|
||||||
permission="zope.View" />-->
|
permission="zope.View" />
|
||||||
|
|
||||||
<page for="loops.interfaces.INode"
|
<page for="loops.interfaces.INode"
|
||||||
name="logout.html"
|
name="logout.html"
|
||||||
class="loops.browser.auth.Logout"
|
class="loops.browser.auth.Logout"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
<!-- see also view/adapter "login.html" in section "query views" -->
|
|
||||||
|
|
||||||
<!-- macros -->
|
<!-- macros -->
|
||||||
|
|
||||||
<page
|
<page
|
||||||
|
@ -113,7 +111,7 @@
|
||||||
name="AddLoopsContainer.html"
|
name="AddLoopsContainer.html"
|
||||||
for="zope.app.container.interfaces.IAdding"
|
for="zope.app.container.interfaces.IAdding"
|
||||||
class="loops.browser.manager.LoopsAddForm"
|
class="loops.browser.manager.LoopsAddForm"
|
||||||
permission="zope.ManageSite"
|
permission="zope.ManageApplication"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<addMenuItem
|
<addMenuItem
|
||||||
|
@ -125,7 +123,7 @@
|
||||||
|
|
||||||
<containerViews
|
<containerViews
|
||||||
for="loops.interfaces.ILoops"
|
for="loops.interfaces.ILoops"
|
||||||
index="zope.ManageSite"
|
index="zope.View"
|
||||||
contents="loops.ManageSite"
|
contents="loops.ManageSite"
|
||||||
add="loops.ManageSite" />
|
add="loops.ManageSite" />
|
||||||
|
|
||||||
|
@ -365,7 +363,7 @@
|
||||||
|
|
||||||
<containerViews
|
<containerViews
|
||||||
for="loops.interfaces.IViewManager"
|
for="loops.interfaces.IViewManager"
|
||||||
index="zope.ManageSite"
|
index="zope.View"
|
||||||
add="loops.ManageSite" />
|
add="loops.ManageSite" />
|
||||||
|
|
||||||
<menuItem
|
<menuItem
|
||||||
|
@ -539,14 +537,6 @@
|
||||||
|
|
||||||
<!-- query views -->
|
<!-- query views -->
|
||||||
|
|
||||||
<!--<zope:adapter
|
|
||||||
name="login.html"
|
|
||||||
for="loops.interfaces.IConcept
|
|
||||||
zope.publisher.interfaces.browser.IBrowserRequest"
|
|
||||||
provides="zope.interface.Interface"
|
|
||||||
factory="loops.browser.auth.LoginConcept"
|
|
||||||
permission="zope.View" />-->
|
|
||||||
|
|
||||||
<zope:adapter
|
<zope:adapter
|
||||||
name="list_children.html"
|
name="list_children.html"
|
||||||
for="loops.interfaces.IConcept
|
for="loops.interfaces.IConcept
|
||||||
|
@ -681,13 +671,6 @@
|
||||||
factory="loops.browser.form.EditConcept"
|
factory="loops.browser.form.EditConcept"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
<page
|
|
||||||
name="test.html"
|
|
||||||
for="loops.interfaces.INode"
|
|
||||||
class="loops.browser.node.TestView"
|
|
||||||
permission="zope.View" />
|
|
||||||
|
|
||||||
|
|
||||||
<!-- inner HTML views -->
|
<!-- inner HTML views -->
|
||||||
|
|
||||||
<page
|
<page
|
|
@ -1,8 +1,28 @@
|
||||||
# loops.browser.external
|
#
|
||||||
|
# Copyright (c) 2008 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" view class(es) for import/export.
|
"""
|
||||||
|
view class(es) for import/export.
|
||||||
|
|
||||||
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from zope.interface import Interface, implements
|
||||||
from zope.app import zapi
|
from zope.app import zapi
|
||||||
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
|
from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,18 +1,35 @@
|
||||||
# loops.browser.form
|
#
|
||||||
|
# Copyright (c) 2014 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Classes for form presentation and processing.
|
"""
|
||||||
|
Classes for form presentation and processing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from urllib.parse import urlencode, unquote_plus
|
from urllib import urlencode
|
||||||
|
from zope.app.container.contained import ObjectRemovedEvent
|
||||||
from zope import component, interface, schema
|
from zope import component, interface, schema
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.container.contained import ObjectRemovedEvent
|
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
from zope.interface import Interface
|
from zope.interface import Interface
|
||||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.container.interfaces import INameChooser
|
from zope.app.container.interfaces import INameChooser
|
||||||
from zope.lifecycleevent import ObjectAddedEvent
|
from zope.app.container.contained import ObjectAddedEvent
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.contenttype import guess_content_type
|
from zope.contenttype import guess_content_type
|
||||||
from zope.publisher.browser import FileUpload
|
from zope.publisher.browser import FileUpload
|
||||||
|
@ -162,14 +179,7 @@ class ObjectForm(NodeView):
|
||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
#overwrite data with values from request.form
|
#overwrite data with values from request.form
|
||||||
if k in self.request.form:
|
if k in self.request.form:
|
||||||
field = self.schema.fields.get(k)
|
data[k] = toUnicode(form[k])
|
||||||
if field:
|
|
||||||
fi = field.getFieldInstance(self.instance)
|
|
||||||
input = form[k]
|
|
||||||
if isinstance(input, str):
|
|
||||||
input = unquote_plus(input)
|
|
||||||
data[k] = fi.marshall(fi.unmarshall(input))
|
|
||||||
#data[k] = toUnicode(form[k])
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -305,7 +315,6 @@ class CreateObjectForm(ObjectForm):
|
||||||
defaultTitle = u'Create Resource, Type = '
|
defaultTitle = u'Create Resource, Type = '
|
||||||
form_action = 'create_resource'
|
form_action = 'create_resource'
|
||||||
dialog_name = 'create'
|
dialog_name = 'create'
|
||||||
setupTarget = False
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def macro(self): return self.template.macros['create']
|
def macro(self): return self.template.macros['create']
|
||||||
|
@ -349,7 +358,6 @@ class CreateObjectForm(ObjectForm):
|
||||||
def adapted(self):
|
def adapted(self):
|
||||||
ad = self.typeInterface(Resource())
|
ad = self.typeInterface(Resource())
|
||||||
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
|
ad.storageName = 'unknown' # hack for file objects: don't try to retrieve data
|
||||||
ad.__is_dummy__ = True
|
|
||||||
ad.__type__ = adapted(self.typeConcept)
|
ad.__type__ = adapted(self.typeConcept)
|
||||||
return ad
|
return ad
|
||||||
|
|
||||||
|
@ -717,20 +725,11 @@ class CreateObject(EditObject):
|
||||||
|
|
||||||
factory = Resource
|
factory = Resource
|
||||||
defaultTypeToken = '.loops/concepts/textdocument'
|
defaultTypeToken = '.loops/concepts/textdocument'
|
||||||
namePrefix = u''
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def container(self):
|
def container(self):
|
||||||
return self.loopsRoot.getResourceManager()
|
return self.loopsRoot.getResourceManager()
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def objectType(self):
|
|
||||||
tc = self.request.form.get('form.type') or self.defaultTypeToken
|
|
||||||
return self.loopsRoot.loopsTraverse(tc)
|
|
||||||
|
|
||||||
def getName(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
def getNameFromData(self):
|
def getNameFromData(self):
|
||||||
data = self.request.form.get('data')
|
data = self.request.form.get('data')
|
||||||
if data and isinstance(data, FileUpload):
|
if data and isinstance(data, FileUpload):
|
||||||
|
@ -749,14 +748,12 @@ class CreateObject(EditObject):
|
||||||
if not title:
|
if not title:
|
||||||
raise BadRequest('Title field is empty')
|
raise BadRequest('Title field is empty')
|
||||||
obj = self.factory(title)
|
obj = self.factory(title)
|
||||||
name = self.getName()
|
name = self.getNameFromData()
|
||||||
if name is None:
|
# TODO: validate fields
|
||||||
name = self.getNameFromData()
|
name = INameChooser(container).chooseName(name, obj)
|
||||||
nc = INameChooser(container)
|
|
||||||
nc.prefix = self.namePrefix
|
|
||||||
name = nc.chooseName(name, obj)
|
|
||||||
container[name] = obj
|
container[name] = obj
|
||||||
obj.setType(self.objectType)
|
tc = form.get('form.type') or self.defaultTypeToken
|
||||||
|
obj.setType(self.loopsRoot.loopsTraverse(tc))
|
||||||
notify(ObjectCreatedEvent(obj))
|
notify(ObjectCreatedEvent(obj))
|
||||||
#notify(ObjectAddedEvent(obj))
|
#notify(ObjectAddedEvent(obj))
|
||||||
self.object = self.view.object = obj
|
self.object = self.view.object = obj
|
||||||
|
@ -811,15 +808,8 @@ class CreateConcept(EditConcept, CreateObject):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def container(self):
|
def container(self):
|
||||||
cmName = adapted(self.objectType).conceptManager
|
|
||||||
if cmName:
|
|
||||||
return self.loopsRoot[cmName]
|
|
||||||
return self.loopsRoot.getConceptManager()
|
return self.loopsRoot.getConceptManager()
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def namePrefix(self):
|
|
||||||
return adapted(self.objectType).namePrefix or u''
|
|
||||||
|
|
||||||
def getNameFromData(self):
|
def getNameFromData(self):
|
||||||
return None
|
return None
|
||||||
|
|
24
loops/browser/form_macros.pt → browser/form_macros.pt
Executable file → Normal file
|
@ -264,10 +264,9 @@
|
||||||
<label style="display: inline"
|
<label style="display: inline"
|
||||||
for="version.create"><span i18n:translate="">
|
for="version.create"><span i18n:translate="">
|
||||||
New version</span></label>
|
New version</span></label>
|
||||||
<tal:level define="versionLevels python:list(view.versionLevels)"
|
<tal:level condition="python: len(view.versionLevels) > 1">:
|
||||||
condition="python: len(versionLevels) > 1">:
|
|
||||||
<select name="version.level">
|
<select name="version.level">
|
||||||
<option tal:repeat="level versionLevels"
|
<option tal:repeat="level view/versionLevels"
|
||||||
i18n:translate=""
|
i18n:translate=""
|
||||||
tal:attributes="value level/token"
|
tal:attributes="value level/token"
|
||||||
tal:content="level/label" />
|
tal:content="level/label" />
|
||||||
|
@ -279,21 +278,17 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:states define-macro="states"
|
<metal:states define-macro="states"
|
||||||
tal:define="states view/states"
|
tal:define="states view/states"
|
||||||
tal:condition="states">
|
tal:condition="states">
|
||||||
<tr><td colspan="5" i18n:translate="" class="headline">States</td></tr>
|
<tr><td colspan="5" i18n:translate="" class="headline">States</td></tr>
|
||||||
<metal:states define-macro="states_info">
|
|
||||||
<tr tal:repeat="st states">
|
<tr tal:repeat="st states">
|
||||||
<tal:state define="stObj st/getStateObject;
|
<tal:state define="stObj st/getStateObject;
|
||||||
stDef st/statesDefinition;
|
stDef st/statesDefinition;
|
||||||
stTrans st/getAvailableTransitionsForUser">
|
stTrans st/getAvailableTransitionsForUser">
|
||||||
<td colspan="2">
|
<td colspan="2" i18n:translate=""
|
||||||
<b i18n:translate=""
|
tal:content="stDef">loops.simple_publishing</td>
|
||||||
tal:content="python:view.translate(stDef, st.msgFactory)">
|
<td i18n:translate=""
|
||||||
loops.simple_publishing</b>: </td>
|
tal:content="stObj/title">draft</td>
|
||||||
<td>
|
|
||||||
<span i18n:translate=""
|
|
||||||
tal:content="stObj/title">draft</span> </td>
|
|
||||||
<td>
|
<td>
|
||||||
<select name="state.loops.simple_publishing"
|
<select name="state.loops.simple_publishing"
|
||||||
tal:condition="stTrans"
|
tal:condition="stTrans"
|
||||||
|
@ -308,7 +303,6 @@
|
||||||
<td />
|
<td />
|
||||||
</tal:state>
|
</tal:state>
|
||||||
</tr>
|
</tr>
|
||||||
</metal:states>
|
|
||||||
</metal:states>
|
</metal:states>
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:info define-macro="object_info"
|
<metal:info define-macro="object_info"
|
||||||
tal:define="item nocall:view/targetItem">
|
tal:define="item nocall:view/item">
|
||||||
<table class="object_info" width="400">
|
<table class="object_info" width="400">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2"><h2 i18n:translate="">Object Information</h2><br /></td>
|
<td colspan="2"><h2 i18n:translate="">Object Information</h2><br /></td>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:info define-macro="meta_info"
|
<metal:info define-macro="meta_info"
|
||||||
tal:define="item nocall:view/targetItem">
|
tal:define="item nocall:view/item">
|
||||||
<table class="object_info" width="400">
|
<table class="object_info" width="400">
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
|
@ -1,9 +1,26 @@
|
||||||
# loops.browser.lobo.standard
|
#
|
||||||
|
# Copyright (c) 2012 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" View classes for lobo (blueprint-based) layouts.
|
"""
|
||||||
|
View classes for lobo (blueprint-based) layouts.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from urllib.parse import parse_qs
|
from cgi import parse_qs
|
||||||
from zope import interface, component
|
from zope import interface, component
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
|
@ -1,6 +1,7 @@
|
||||||
# loops.browser.lobo.tests
|
# $Id$
|
||||||
|
|
||||||
import unittest, doctest
|
import unittest, doctest
|
||||||
|
from zope.testing.doctestunit import DocFileSuite
|
||||||
from zope.interface.verify import verifyClass
|
from zope.interface.verify import verifyClass
|
||||||
|
|
||||||
class Test(unittest.TestCase):
|
class Test(unittest.TestCase):
|
||||||
|
@ -13,9 +14,9 @@ class Test(unittest.TestCase):
|
||||||
def test_suite():
|
def test_suite():
|
||||||
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
flags = doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS
|
||||||
return unittest.TestSuite((
|
return unittest.TestSuite((
|
||||||
unittest.TestLoader().loadTestsFromTestCase(Test),
|
unittest.makeSuite(Test),
|
||||||
doctest.DocFileSuite('README.txt', optionflags=flags),
|
DocFileSuite('README.txt', optionflags=flags),
|
||||||
))
|
))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main(defaultTest='test_suite')
|
unittest.main(defaultTest='test_suite')
|
26
loops/browser/loops.js → browser/loops.js
Executable file → Normal file
|
@ -42,7 +42,7 @@ function showIf(node, value, targetName) {
|
||||||
|
|
||||||
function showIfIn(node, conditions) {
|
function showIfIn(node, conditions) {
|
||||||
dojo.forEach(conditions, function(cond) {
|
dojo.forEach(conditions, function(cond) {
|
||||||
var display = (node.value == cond[0]) ? '' : 'none';
|
var display = (node.value == cond[0]) ? 'inline' : 'none';
|
||||||
dojo.byId(cond[1]).style.display = display;
|
dojo.byId(cond[1]).style.display = display;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -56,26 +56,6 @@ function setIfIn(node, conditions) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function setIf(node, cond, acts) {
|
|
||||||
if (node.value == cond) {
|
|
||||||
dojo.forEach(acts, function(act) {
|
|
||||||
target = dijit.byId(act[0]);
|
|
||||||
target.setValue(act[1]);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setIfN(node, conds, acts) {
|
|
||||||
dojo.forEach(conds, function(cond) {
|
|
||||||
if (node.value == cond) {
|
|
||||||
dojo.forEach(acts, function(act) {
|
|
||||||
target = dijit.byId(act[0]);
|
|
||||||
target.setValue(act[1]);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
function destroyWidgets(node) {
|
function destroyWidgets(node) {
|
||||||
dojo.forEach(dojo.query('[widgetId]', node), function(n) {
|
dojo.forEach(dojo.query('[widgetId]', node), function(n) {
|
||||||
w = dijit.byNode(n);
|
w = dijit.byNode(n);
|
||||||
|
@ -132,7 +112,7 @@ function submitReplacing(targetId, formId, url) {
|
||||||
mimetype: "text/html",
|
mimetype: "text/html",
|
||||||
load: function(response, ioArgs) {
|
load: function(response, ioArgs) {
|
||||||
replaceNode(response, targetId);
|
replaceNode(response, targetId);
|
||||||
return response;
|
return resonse;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -144,7 +124,7 @@ function xhrSubmitPopup(formId, url) {
|
||||||
mimetype: "text/html",
|
mimetype: "text/html",
|
||||||
load: function(response, ioArgs) {
|
load: function(response, ioArgs) {
|
||||||
window.close();
|
window.close();
|
||||||
return response;
|
return resonse;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 942 B |
|
@ -1,5 +1,5 @@
|
||||||
#
|
#
|
||||||
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
# Copyright (c) 2006 Helmut Merz helmutm@cy55.de
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
@ -22,6 +22,7 @@ Definition of view classes for the top-level loops container.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from zope.app import zapi
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.event import notify
|
from zope.event import notify
|
|
@ -1,11 +1,31 @@
|
||||||
# loops.browser.mobile.default
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Default layouts for the loops mobile skin.
|
"""
|
||||||
|
Default layouts for the loops mobile skin.
|
||||||
|
|
||||||
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope.app.pagetemplate import ViewPageTemplateFile
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope import component
|
from zope import component
|
||||||
|
from zope.interface import implements
|
||||||
|
|
||||||
from cybertools.browser.renderer import RendererFactory
|
from cybertools.browser.renderer import RendererFactory
|
||||||
from cybertools.composer.layout.base import Layout
|
from cybertools.composer.layout.base import Layout
|
170
loops/browser/node.py → browser/node.py
Executable file → Normal file
|
@ -1,28 +1,42 @@
|
||||||
# loops.browser.node
|
#
|
||||||
|
# Copyright (c) 2015 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" View class for Node objects.
|
"""
|
||||||
|
View class for Node objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from logging import getLogger
|
from urlparse import urlparse, urlunparse
|
||||||
from urllib.parse import urlencode, urlparse, urlunparse
|
from zope import component, interface, schema
|
||||||
#from urlparse import urlparse, urlunparse
|
from zope.cachedescriptors.property import Lazy
|
||||||
|
from zope.annotation.interfaces import IAnnotations
|
||||||
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.app.container.browser.contents import JustContents
|
from zope.app.container.browser.contents import JustContents
|
||||||
from zope.app.container.browser.adding import Adding
|
from zope.app.container.browser.adding import Adding
|
||||||
from zope import component, interface, schema
|
from zope.app.container.traversal import ItemTraverser
|
||||||
from zope.annotation.interfaces import IAnnotations
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
|
||||||
from zope.cachedescriptors.property import Lazy
|
|
||||||
from zope.catalog.interfaces import ICatalog
|
|
||||||
from zope.container.traversal import ItemTraverser
|
|
||||||
from zope.dottedname.resolve import resolve
|
from zope.dottedname.resolve import resolve
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
from zope.lifecycleevent import ObjectCreatedEvent, ObjectModifiedEvent
|
||||||
from zope.lifecycleevent import Attributes
|
from zope.lifecycleevent import Attributes
|
||||||
from zope.formlib.form import Form, FormFields
|
from zope.formlib.form import Form, FormFields
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.publisher.defaultview import getDefaultViewName
|
from zope.app.publisher.browser import getDefaultViewName
|
||||||
from zope.publisher.interfaces import NotFound
|
|
||||||
from zope.security import canAccess, canWrite, checkPermission
|
from zope.security import canAccess, canWrite, checkPermission
|
||||||
from zope.security.proxy import removeSecurityProxy
|
from zope.security.proxy import removeSecurityProxy
|
||||||
from zope.traversing.api import getParent, getParents, getPath
|
from zope.traversing.api import getParent, getParents, getPath
|
||||||
|
@ -51,7 +65,6 @@ from loops import util
|
||||||
from loops.util import _
|
from loops.util import _
|
||||||
from loops.versioning.util import getVersion
|
from loops.versioning.util import getVersion
|
||||||
|
|
||||||
logger = getLogger('loops.browser.node')
|
|
||||||
|
|
||||||
node_macros = ViewPageTemplateFile('node_macros.pt')
|
node_macros = ViewPageTemplateFile('node_macros.pt')
|
||||||
info_macros = ViewPageTemplateFile('info.pt')
|
info_macros = ViewPageTemplateFile('info.pt')
|
||||||
|
@ -63,71 +76,26 @@ class NodeView(BaseView):
|
||||||
_itemNum = 0
|
_itemNum = 0
|
||||||
template = node_macros
|
template = node_macros
|
||||||
nextUrl = None
|
nextUrl = None
|
||||||
setupTarget = True
|
|
||||||
|
|
||||||
def __init__(self, context, request):
|
def __init__(self, context, request):
|
||||||
super(NodeView, self).__init__(context, request)
|
super(NodeView, self).__init__(context, request)
|
||||||
self.viewAnnotations.setdefault('nodeView', self)
|
self.viewAnnotations.setdefault('nodeView', self)
|
||||||
self.viewAnnotations.setdefault('node', self.context)
|
self.viewAnnotations.setdefault('node', self.context)
|
||||||
self.setSkin(self.viewConfig.get('skinName'))
|
viewConfig = getViewConfiguration(context, request)
|
||||||
|
self.setSkin(viewConfig.get('skinName'))
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
def __call__(self, *args, **kw):
|
||||||
if self.nodeType == 'raw':
|
|
||||||
vn = self.context.viewName
|
|
||||||
if vn:
|
|
||||||
self.request.response.setHeader('content-type', vn)
|
|
||||||
return self.context.body
|
|
||||||
tv = self.viewAnnotations.get('targetView')
|
tv = self.viewAnnotations.get('targetView')
|
||||||
if tv is not None:
|
if tv is not None:
|
||||||
if tv.isToplevel:
|
if tv.isToplevel:
|
||||||
return tv(*args, **kw)
|
return tv(*args, **kw)
|
||||||
if self.controller is not None:
|
|
||||||
self.controller.setMainPage()
|
|
||||||
return super(NodeView, self).__call__(*args, **kw)
|
return super(NodeView, self).__call__(*args, **kw)
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def viewConfig(self):
|
|
||||||
return getViewConfiguration(self.context, self.request)
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def viewConfigOptions(self):
|
|
||||||
result = {}
|
|
||||||
for opt in self.viewConfig.get('options') or []:
|
|
||||||
if ':' in opt:
|
|
||||||
k, v = opt.split(':', 1)
|
|
||||||
result[k] = v.split(',')
|
|
||||||
else:
|
|
||||||
result[opt] = True
|
|
||||||
return result
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def copyright(self):
|
|
||||||
cr = self.viewConfigOptions.get('copyright')
|
|
||||||
if cr:
|
|
||||||
return cr[0]
|
|
||||||
cr = self.globalOptions('copyright')
|
|
||||||
return cr and cr[0] or 'cyberconcepts.org team'
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def macro(self):
|
def macro(self):
|
||||||
return self.template.macros['content']
|
return self.template.macros['content']
|
||||||
|
|
||||||
@Lazy
|
def update(self):
|
||||||
def subparts(self):
|
|
||||||
def getParts(n):
|
|
||||||
t = n.targetObjectView
|
|
||||||
if t is None:
|
|
||||||
return []
|
|
||||||
return t.subparts
|
|
||||||
parts = getParts(self)
|
|
||||||
#return parts
|
|
||||||
for n in self.textItems:
|
|
||||||
parts.extend(getParts(n))
|
|
||||||
return parts
|
|
||||||
|
|
||||||
def update(self, topLevel=True):
|
|
||||||
if topLevel and self.view != self:
|
|
||||||
return self.view.update(False)
|
|
||||||
result = super(NodeView, self).update()
|
result = super(NodeView, self).update()
|
||||||
self.recordAccess()
|
self.recordAccess()
|
||||||
return result
|
return result
|
||||||
|
@ -381,10 +349,6 @@ class NodeView(BaseView):
|
||||||
def editable(self):
|
def editable(self):
|
||||||
return canWrite(self.context, 'body')
|
return canWrite(self.context, 'body')
|
||||||
|
|
||||||
def hasTopPage(self, name):
|
|
||||||
page = self.topMenu.context.get(name)
|
|
||||||
return page is not None
|
|
||||||
|
|
||||||
# menu stuff
|
# menu stuff
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -430,9 +394,8 @@ class NodeView(BaseView):
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def menuItems(self):
|
def menuItems(self):
|
||||||
items = [NodeView(child, self.request).view
|
return [NodeView(child, self.request)
|
||||||
for child in self.context.getMenuItems()]
|
for child in self.context.getMenuItems()]
|
||||||
return [item for item in items if item.isVisible]
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def parents(self):
|
def parents(self):
|
||||||
|
@ -460,15 +423,6 @@ class NodeView(BaseView):
|
||||||
def active(self, item):
|
def active(self, item):
|
||||||
return item.context == self.context or item.context in self.parents
|
return item.context == self.context or item.context in self.parents
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def logoutUrl(self):
|
|
||||||
nextUrl = urlencode(dict(nextUrl=self.menu.url))
|
|
||||||
return '%s/logout.html?%s' % (self.menu.url, nextUrl)
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def authenticationMethod(self):
|
|
||||||
return self.viewAnnotations.get('auth_method') or 'standard'
|
|
||||||
|
|
||||||
# virtual target support
|
# virtual target support
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -544,8 +498,7 @@ class NodeView(BaseView):
|
||||||
if tv is not None:
|
if tv is not None:
|
||||||
tv.setupController()
|
tv.setupController()
|
||||||
return tv
|
return tv
|
||||||
setup = self.setupTarget
|
return self.getViewForTarget(self.virtualTargetObject)
|
||||||
return self.getViewForTarget(self.virtualTargetObject, setup=setup)
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def targetId(self):
|
def targetId(self):
|
||||||
|
@ -581,7 +534,7 @@ class NodeView(BaseView):
|
||||||
@Lazy
|
@Lazy
|
||||||
def typeProvider(self):
|
def typeProvider(self):
|
||||||
if self.virtualTargetObject is not None:
|
if self.virtualTargetObject is not None:
|
||||||
return IType(baseObject(self.virtualTargetObject)).typeProvider
|
return IType(self.virtualTargetObject).typeProvider
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# target viewing and editing support
|
# target viewing and editing support
|
||||||
|
@ -590,38 +543,24 @@ class NodeView(BaseView):
|
||||||
""" Return URL of given target view given as .XXX URL.
|
""" Return URL of given target view given as .XXX URL.
|
||||||
"""
|
"""
|
||||||
if isinstance(target, BaseView):
|
if isinstance(target, BaseView):
|
||||||
miu = self.getMenuItemUrlForTarget(target.context)
|
|
||||||
if miu is not None:
|
|
||||||
return miu
|
|
||||||
return self.makeTargetUrl(self.url, target.uniqueId, target.title)
|
return self.makeTargetUrl(self.url, target.uniqueId, target.title)
|
||||||
else:
|
else:
|
||||||
target = baseObject(target)
|
target = baseObject(target)
|
||||||
return self.makeTargetUrl(self.url, util.getUidForObject(target),
|
return self.makeTargetUrl(self.url, util.getUidForObject(target),
|
||||||
target.title)
|
target.title)
|
||||||
|
|
||||||
def getMenuItemUrlForTarget(self, tobj):
|
|
||||||
for node in tobj.getClients():
|
|
||||||
if node.nodeType == 'page' and node.getMenu() == self.menuObject:
|
|
||||||
return absoluteURL(node, self.request)
|
|
||||||
|
|
||||||
|
|
||||||
def getActions(self, category='object', page=None, target=None):
|
def getActions(self, category='object', page=None, target=None):
|
||||||
actions = []
|
actions = []
|
||||||
#self.registerDojo()
|
#self.registerDojo()
|
||||||
self.registerDojoFormAll()
|
self.registerDojoFormAll()
|
||||||
if target is None:
|
if target is None:
|
||||||
target = self.virtualTarget
|
target = self.virtualTarget
|
||||||
#target = self.getViewForTarget(self.virtualTargetObject,
|
|
||||||
# setup=False)
|
|
||||||
if category in self.actions:
|
if category in self.actions:
|
||||||
actions.extend(self.actions[category](self, target=target))
|
actions.extend(self.actions[category](self, target=target))
|
||||||
if target is not None and self.setupTarget:
|
if target is not None:
|
||||||
actions.extend(target.getActions(
|
actions.extend(target.getActions(category, page=self, target=target))
|
||||||
category, page=self, target=target))
|
if target != self.virtualTarget: # self view must be used directly for target
|
||||||
if target is not None and target.context != self.virtualTargetObject:
|
actions.extend(self.view.getAdditionalActions(category, self, target))
|
||||||
# self view must be used directly for target
|
|
||||||
actions.extend(self.view.getAdditionalActions(
|
|
||||||
category, self, target))
|
|
||||||
return actions
|
return actions
|
||||||
|
|
||||||
def getPortletActions(self, target=None):
|
def getPortletActions(self, target=None):
|
||||||
|
@ -643,6 +582,7 @@ class NodeView(BaseView):
|
||||||
actions = dict(portlet=getPortletActions)
|
actions = dict(portlet=getPortletActions)
|
||||||
|
|
||||||
def checkAction(self, name, category, target):
|
def checkAction(self, name, category, target):
|
||||||
|
#if name in ('create_resource',) and target is not None:
|
||||||
if target is not None:
|
if target is not None:
|
||||||
return target.checkAction(name, category, target)
|
return target.checkAction(name, category, target)
|
||||||
return super(NodeView, self).checkAction(name, category, target)
|
return super(NodeView, self).checkAction(name, category, target)
|
||||||
|
@ -769,11 +709,11 @@ class InlineEdit(NodeView):
|
||||||
if ti is not None:
|
if ti is not None:
|
||||||
target = ti(target)
|
target = ti(target)
|
||||||
data = self.request.form['editorContent']
|
data = self.request.form['editorContent']
|
||||||
if not isinstance(data, str):
|
if type(data) != unicode:
|
||||||
try:
|
try:
|
||||||
data = data.decode('ISO-8859-15') # IE hack
|
data = data.decode('ISO-8859-15') # IE hack
|
||||||
except UnicodeDecodeError:
|
except UnicodeDecodeError:
|
||||||
print('loops.browser.node.InlineEdit.save():', data)
|
print 'loops.browser.node.InlineEdit.save():', data
|
||||||
return
|
return
|
||||||
# data = data.decode('UTF-8')
|
# data = data.decode('UTF-8')
|
||||||
target.data = data
|
target.data = data
|
||||||
|
@ -945,9 +885,9 @@ class NodeAdding(Adding):
|
||||||
return info
|
return info
|
||||||
|
|
||||||
|
|
||||||
@interface.implementer(IViewConfiguratorSchema)
|
|
||||||
class ViewPropertiesConfigurator(object):
|
class ViewPropertiesConfigurator(object):
|
||||||
|
|
||||||
|
interface.implements(IViewConfiguratorSchema)
|
||||||
component.adapts(INode)
|
component.adapts(INode)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
|
@ -1033,12 +973,7 @@ class NodeTraverser(ItemTraverser):
|
||||||
viewAnnotations['targetView'] = view
|
viewAnnotations['targetView'] = view
|
||||||
view.logInfo('NodeTraverser:targetView = %r' % view)
|
view.logInfo('NodeTraverser:targetView = %r' % view)
|
||||||
return self.context
|
return self.context
|
||||||
try:
|
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
||||||
obj = super(NodeTraverser, self).publishTraverse(request, name)
|
|
||||||
except NotFound:
|
|
||||||
logger.warn('NodeTraverser: NotFound: URL = %s, name = %r' %
|
|
||||||
(request.URL, name))
|
|
||||||
raise
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
def getTargetUid(self, request):
|
def getTargetUid(self, request):
|
||||||
|
@ -1086,9 +1021,7 @@ def setViewConfiguration(context, request):
|
||||||
config = IViewConfiguratorSchema(context)
|
config = IViewConfiguratorSchema(context)
|
||||||
skinName = config.skinName
|
skinName = config.skinName
|
||||||
if not skinName:
|
if not skinName:
|
||||||
root = removeSecurityProxy(context.getLoopsRoot())
|
skinName = context.getLoopsRoot().skinName
|
||||||
skinName = root.skinName
|
|
||||||
#skinName = context.getLoopsRoot().skinName
|
|
||||||
if skinName:
|
if skinName:
|
||||||
viewAnnotations['skinName'] = skinName
|
viewAnnotations['skinName'] = skinName
|
||||||
if config.options:
|
if config.options:
|
||||||
|
@ -1101,18 +1034,3 @@ def getViewConfiguration(context, request):
|
||||||
viewAnnotations = request.annotations.get('loops.view', {})
|
viewAnnotations = request.annotations.get('loops.view', {})
|
||||||
return dict(skinName=viewAnnotations.get('skinName'),
|
return dict(skinName=viewAnnotations.get('skinName'),
|
||||||
options=viewAnnotations.get('options'))
|
options=viewAnnotations.get('options'))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TestView(NodeView):
|
|
||||||
|
|
||||||
def __call__(self):
|
|
||||||
print( '*** begin')
|
|
||||||
for i in range(500):
|
|
||||||
#x = util.getObjectForUid('1994729849')
|
|
||||||
x = util.getObjectForUid('2018653366')
|
|
||||||
self.c = list(x.getChildren())
|
|
||||||
#self.c = list(x.getChildren([self.defaultPredicate]))
|
|
||||||
print('*** end', len(self.c))
|
|
||||||
return 'done'
|
|
||||||
|
|
Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 942 B |
|
@ -276,17 +276,6 @@
|
||||||
title mode/description"
|
title mode/description"
|
||||||
tal:content="mode/title"
|
tal:content="mode/title"
|
||||||
i18n:translate="" />
|
i18n:translate="" />
|
||||||
<ul class="sub-view-modes"
|
|
||||||
tal:define="subModes mode/subViewModes|nothing"
|
|
||||||
tal:condition="subModes">
|
|
||||||
<li tal:repeat="mode subModes"
|
|
||||||
tal:attributes="class mode/cssClass">
|
|
||||||
<a tal:attributes="href mode/url;
|
|
||||||
title mode/description;"
|
|
||||||
tal:content="mode/title"
|
|
||||||
i18n:translate=""></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</metal:actions>
|
</metal:actions>
|
||||||
|
@ -298,8 +287,7 @@
|
||||||
tal:condition="python: 'print' in pageActions"
|
tal:condition="python: 'print' in pageActions"
|
||||||
title="Print this page"
|
title="Print this page"
|
||||||
i18n:attributes="title">
|
i18n:attributes="title">
|
||||||
<a href="#"
|
<a href="javascript:print()">
|
||||||
onclick="print(); return false;">
|
|
||||||
<img tal:attributes="src string:$resourceBase/cybertools.icons/printer.png"
|
<img tal:attributes="src string:$resourceBase/cybertools.icons/printer.png"
|
||||||
i18n:attributes="alt"
|
i18n:attributes="alt"
|
||||||
alt="Print" />
|
alt="Print" />
|
||||||
|
@ -333,18 +321,18 @@
|
||||||
<metal:login define-macro="login">
|
<metal:login define-macro="login">
|
||||||
<div>
|
<div>
|
||||||
<a href="login.html"
|
<a href="login.html"
|
||||||
tal:attributes="href string:${view/topMenu/url}/login.html"
|
i18n:translate="">Log in</a></div>
|
||||||
i18n:translate="">Log in</a></div>
|
|
||||||
<div tal:define="register python:view.globalOptions('provideLogin')"
|
<div tal:define="register python:view.globalOptions('provideLogin')"
|
||||||
tal:condition="python:register and register != True">
|
tal:condition="register">
|
||||||
<a tal:define="reg python:register[0]"
|
<a tal:condition="python:register != True"
|
||||||
tal:attributes="href string:${view/topMenu/url}/$reg"
|
tal:attributes="href python:register[0]"
|
||||||
i18n:translate="">Register new member</a></div>
|
i18n:translate="">Register new member</a></div>
|
||||||
</metal:login>
|
</metal:login>
|
||||||
|
|
||||||
|
|
||||||
<metal:actions define-macro="personal">
|
<metal:actions define-macro="personal">
|
||||||
<div><a tal:attributes="href view/logoutUrl"
|
<div><a href="logout.html?nextURL=login.html"
|
||||||
|
tal:attributes="href string:logout.html?nextURL=${view/menu/url}"
|
||||||
i18n:translate="">Log out</a></div>
|
i18n:translate="">Log out</a></div>
|
||||||
<tal:actions repeat="action python:view.getAllowedActions('personal')">
|
<tal:actions repeat="action python:view.getAllowedActions('personal')">
|
||||||
<metal:action use-macro="action/macro" />
|
<metal:action use-macro="action/macro" />
|
|
@ -18,6 +18,10 @@
|
||||||
<a href="#"
|
<a href="#"
|
||||||
tal:attributes="href string:${target/url}/@@configure.html"
|
tal:attributes="href string:${target/url}/@@configure.html"
|
||||||
tal:content="target/title">Document xy</a>
|
tal:content="target/title">Document xy</a>
|
||||||
|
<tal:xedit define="xeditObjectUrl target/url"
|
||||||
|
condition="target/xeditable">
|
||||||
|
<metal:xedit use-macro="views/xedit_macros/editLink" />
|
||||||
|
</tal:xedit>
|
||||||
</tal:target>
|
</tal:target>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -52,7 +52,7 @@
|
||||||
tal:attributes="value item/token" />
|
tal:attributes="value item/token" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a tal:content="item/title|string:???"
|
<a tal:content="item/title"
|
||||||
tal:attributes="href string:${item/url}/@@SelectedManagementView.html">
|
tal:attributes="href string:${item/url}/@@SelectedManagementView.html">
|
||||||
Title
|
Title
|
||||||
</a>
|
</a>
|
|
@ -1,18 +1,36 @@
|
||||||
# loops.browser.resource
|
#
|
||||||
|
# Copyright (c) 2015 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" View class for resource objects.
|
"""
|
||||||
|
View class for resource objects.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
from zope.authentication.interfaces import IUnauthenticatedPrincipal
|
import urllib
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.catalog.interfaces import ICatalog
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.container.interfaces import INameChooser
|
from zope.app.container.interfaces import INameChooser
|
||||||
|
from zope.app.form.browser.textwidgets import FileWidget
|
||||||
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
|
from zope.app.security.interfaces import IUnauthenticatedPrincipal
|
||||||
from zope.formlib.form import FormFields
|
from zope.formlib.form import FormFields
|
||||||
from zope.formlib.interfaces import DISPLAY_UNWRITEABLE
|
from zope.formlib.interfaces import DISPLAY_UNWRITEABLE
|
||||||
from zope.formlib.textwidgets import FileWidget
|
|
||||||
from zope.proxy import removeAllProxies
|
from zope.proxy import removeAllProxies
|
||||||
from zope.schema.interfaces import IBytes
|
from zope.schema.interfaces import IBytes
|
||||||
from zope.security import canAccess, canWrite
|
from zope.security import canAccess, canWrite
|
||||||
|
@ -171,7 +189,7 @@ class ResourceView(BaseView):
|
||||||
return DocumentView(context, self.request)
|
return DocumentView(context, self.request)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def show(self, useAttachment=False, filename=None):
|
def show(self, useAttachment=False):
|
||||||
""" show means: "download"..."""
|
""" show means: "download"..."""
|
||||||
# TODO: control access, e.g. to protected images
|
# TODO: control access, e.g. to protected images
|
||||||
# if self.adapted.isProtected():
|
# if self.adapted.isProtected():
|
||||||
|
@ -179,9 +197,6 @@ class ResourceView(BaseView):
|
||||||
context = self.context
|
context = self.context
|
||||||
ct = context.contentType
|
ct = context.contentType
|
||||||
response = self.request.response
|
response = self.request.response
|
||||||
if self.typeOptions('x_robots_tag_header', None) is not None:
|
|
||||||
tagVal = ', '.join(self.typeOptions('x_robots_tag_header'))
|
|
||||||
response.setHeader('X-Robots-Tag', tagVal)
|
|
||||||
self.recordAccess('show', target=self.uniqueId)
|
self.recordAccess('show', target=self.uniqueId)
|
||||||
if ct.startswith('image/'):
|
if ct.startswith('image/'):
|
||||||
#response.setHeader('Cache-Control', 'public,max-age=86400')
|
#response.setHeader('Cache-Control', 'public,max-age=86400')
|
||||||
|
@ -191,27 +206,22 @@ class ResourceView(BaseView):
|
||||||
from loops.media.browser.asset import MediaAssetView
|
from loops.media.browser.asset import MediaAssetView
|
||||||
view = MediaAssetView(context, self.request)
|
view = MediaAssetView(context, self.request)
|
||||||
return view.show(useAttachment)
|
return view.show(useAttachment)
|
||||||
else:
|
|
||||||
response.setHeader('Cache-Control', '')
|
|
||||||
response.setHeader('Pragma', '')
|
|
||||||
ti = IType(context).typeInterface
|
ti = IType(context).typeInterface
|
||||||
if ti is not None:
|
if ti is not None:
|
||||||
context = ti(context)
|
context = ti(context)
|
||||||
data = context.data
|
data = context.data
|
||||||
if useAttachment:
|
if useAttachment:
|
||||||
if filename is None:
|
filename = adapted(self.context).localFilename or getName(self.context)
|
||||||
filename = (adapted(self.context).localFilename or
|
if self.typeOptions('use_title_for_download_filename'):
|
||||||
getName(self.context))
|
base, ext = os.path.splitext(filename)
|
||||||
if self.typeOptions('use_title_for_download_filename'):
|
filename = context.title
|
||||||
base, ext = os.path.splitext(filename)
|
vr = IVersionable(baseObject(context))
|
||||||
filename = context.title
|
if len(vr.versions) > 0:
|
||||||
vr = IVersionable(baseObject(context))
|
filename = vr.generateName(filename, ext, vr.versionId)
|
||||||
if len(vr.versions) > 0:
|
else:
|
||||||
filename = vr.generateName(filename, ext, vr.versionId)
|
if not filename.endswith(ext):
|
||||||
else:
|
filename += ext
|
||||||
if not filename.endswith(ext):
|
filename = filename.encode('UTF-8')
|
||||||
filename += ext
|
|
||||||
filename = filename.encode('UTF-8')
|
|
||||||
if self.typeOptions('no_normalize_download_filename'):
|
if self.typeOptions('no_normalize_download_filename'):
|
||||||
filename = '"%s"' % filename
|
filename = '"%s"' % filename
|
||||||
else:
|
else:
|
||||||
|
@ -254,21 +264,15 @@ class ResourceView(BaseView):
|
||||||
#wp = wiki.createPage(getName(self.context))
|
#wp = wiki.createPage(getName(self.context))
|
||||||
wp = wiki.addPage(LoopsWikiPage(self.context))
|
wp = wiki.addPage(LoopsWikiPage(self.context))
|
||||||
wp.text = text
|
wp.text = text
|
||||||
#print(wp.wiki.getManager())
|
#print wp.wiki.getManager()
|
||||||
#return util.toUnicode(wp.render(self.request))
|
#return util.toUnicode(wp.render(self.request))
|
||||||
return super(ResourceView, self).renderText(text, contentType)
|
return super(ResourceView, self).renderText(text, contentType)
|
||||||
|
|
||||||
showMore = True
|
|
||||||
|
|
||||||
def renderShortText(self):
|
def renderShortText(self):
|
||||||
return self.renderDescription() or self.createShortText(self.render())
|
return self.renderDescription() or self.createShortText(self.render())
|
||||||
|
|
||||||
def createShortText(self, text=None):
|
def createShortText(self, text=None):
|
||||||
text = (text or self.render()).strip()
|
return extractFirstPart(text or self.render())
|
||||||
shortText = extractFirstPart(text)
|
|
||||||
if shortText == text:
|
|
||||||
self.showMore = False
|
|
||||||
return shortText
|
|
||||||
|
|
||||||
def download(self):
|
def download(self):
|
||||||
""" Force download, e.g. of a PDF file """
|
""" Force download, e.g. of a PDF file """
|
||||||
|
@ -449,7 +453,7 @@ class ExternalEditorView(ExternalEditorView, BaseView):
|
||||||
r.append('meta_type:' + '.'.join((context.__module__, context.__class__.__name__)))
|
r.append('meta_type:' + '.'.join((context.__module__, context.__class__.__name__)))
|
||||||
auth = self.request.get('_auth')
|
auth = self.request.get('_auth')
|
||||||
if auth:
|
if auth:
|
||||||
print('ExternalEditorView: auth = ', auth)
|
print 'ExternalEditorView: auth = ', auth
|
||||||
if auth.endswith('\n'):
|
if auth.endswith('\n'):
|
||||||
auth = auth[:-1]
|
auth = auth[:-1]
|
||||||
r.append('auth:' + auth)
|
r.append('auth:' + auth)
|
||||||
|
@ -473,3 +477,4 @@ class NoteView(DocumentView):
|
||||||
def linkUrl(self):
|
def linkUrl(self):
|
||||||
ad = self.typeAdapter
|
ad = self.typeAdapter
|
||||||
return ad and ad.linkUrl or ''
|
return ad and ad.linkUrl or ''
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
<div metal:use-macro="views/node_macros/object_actions" />
|
<div metal:use-macro="views/node_macros/object_actions" />
|
||||||
</tal:actions>
|
</tal:actions>
|
||||||
<h1><a tal:omit-tag="python: level > 1"
|
<h1><a tal:omit-tag="python: level > 1"
|
||||||
tal:attributes="href view/requestUrl"
|
tal:attributes="href request/URL"
|
||||||
tal:content="item/title">Title</a></h1>
|
tal:content="item/title">Title</a></h1>
|
||||||
<tal:desc define="description description|item/renderedDescription"
|
<tal:desc define="description description|item/renderedDescription"
|
||||||
condition="description">
|
condition="description">
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
<div tal:attributes="ondblclick python: item.openEditWindow('edit.html')">
|
||||||
<div metal:use-macro="views/node_macros/object_actions" />
|
<div metal:use-macro="views/node_macros/object_actions" />
|
||||||
<h1><a tal:omit-tag="python: level > 1"
|
<h1><a tal:omit-tag="python: level > 1"
|
||||||
tal:attributes="href view/requestUrl"
|
tal:attributes="href request/URL"
|
||||||
tal:content="item/title">Title</a></h1><br />
|
tal:content="item/title">Title</a></h1><br />
|
||||||
<img tal:attributes="src
|
<img tal:attributes="src
|
||||||
string:${view/url}/.${view/targetId}/view?version=this" />
|
string:${view/url}/.${view/targetId}/view?version=this" />
|
||||||
|
@ -72,7 +72,6 @@
|
||||||
<div>
|
<div>
|
||||||
<span class="button">
|
<span class="button">
|
||||||
<a i18n:translate=""
|
<a i18n:translate=""
|
||||||
target="_blank"
|
|
||||||
tal:attributes="href
|
tal:attributes="href
|
||||||
string:${view/virtualTargetUrl}/download.html?version=this">
|
string:${view/virtualTargetUrl}/download.html?version=this">
|
||||||
Download
|
Download
|
|
@ -1,4 +1,6 @@
|
||||||
# package loops.browser.skin
|
"""
|
||||||
|
$Id$
|
||||||
|
"""
|
||||||
|
|
||||||
from cybertools.browser.liquid import Liquid
|
from cybertools.browser.liquid import Liquid
|
||||||
from cybertools.browser.blue import Blue
|
from cybertools.browser.blue import Blue
|
|
@ -18,11 +18,6 @@
|
||||||
permission="zope.View"
|
permission="zope.View"
|
||||||
layer="loops.browser.skin.Loopy" />
|
layer="loops.browser.skin.Loopy" />
|
||||||
|
|
||||||
<page for="*"
|
|
||||||
name="loopy.body_macros"
|
|
||||||
template="loopy/body.pt"
|
|
||||||
permission="zope.Public" />
|
|
||||||
|
|
||||||
<resource name="loops.css" file="loopy/loops.css"
|
<resource name="loops.css" file="loopy/loops.css"
|
||||||
layer="loops.browser.skin.Loopy" />
|
layer="loops.browser.skin.Loopy" />
|
||||||
<resource name="custom.css" file="loopy/custom.css"
|
<resource name="custom.css" file="loopy/custom.css"
|
|
@ -25,7 +25,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="content" class="span-6"
|
<div id="content" class="span-6"
|
||||||
tal:attributes="class content_class|string:span-6"
|
|
||||||
metal:define-macro="content">
|
metal:define-macro="content">
|
||||||
<metal:breadcrumbs define-slot="breadcrumbs">
|
<metal:breadcrumbs define-slot="breadcrumbs">
|
||||||
<metal:tabs use-macro="views/node_macros/breadcrumbs" />
|
<metal:tabs use-macro="views/node_macros/breadcrumbs" />
|
||||||
|
@ -38,9 +37,7 @@
|
||||||
tal:condition="msg"
|
tal:condition="msg"
|
||||||
tal:content="msg" />
|
tal:content="msg" />
|
||||||
</metal:message>
|
</metal:message>
|
||||||
<metal:tabs define-slot="view_modes">
|
<metal:tabs use-macro="views/node_macros/view_modes" />
|
||||||
<metal:tabs use-macro="views/node_macros/view_modes" />
|
|
||||||
</metal:tabs>
|
|
||||||
<metal:content define-slot="content">
|
<metal:content define-slot="content">
|
||||||
<tal:content define="item nocall:view/item;
|
<tal:content define="item nocall:view/item;
|
||||||
level level|python: 1;
|
level level|python: 1;
|
||||||
|
@ -51,27 +48,22 @@
|
||||||
</metal:content>
|
</metal:content>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="portlets" class="span-2 last"
|
<div id="portlets" class="span-2 last">
|
||||||
tal:attributes="class portlets_class|string:span-2 last">
|
<tal:portlet repeat="macro controller/macros/portlet_left">
|
||||||
<metal:portlet define-slot="portlet-left" >
|
<metal:portlet use-macro="macro" />
|
||||||
<tal:portlet repeat="macro controller/macros/portlet_left">
|
</tal:portlet>
|
||||||
<metal:portlet use-macro="macro" />
|
<tal:portlet repeat="macro controller/macros/portlet_right">
|
||||||
</tal:portlet>
|
<metal:portlet use-macro="macro" />
|
||||||
</metal:portlet>
|
</tal:portlet>
|
||||||
<metal:portlet define-slot="portlet-right" >
|
|
||||||
<tal:portlet repeat="macro controller/macros/portlet_right">
|
|
||||||
<metal:portlet use-macro="macro" />
|
|
||||||
</tal:portlet>
|
|
||||||
</metal:portlet>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="footer" class="footer clear"
|
<div id="footer" class="footer clear"
|
||||||
metal:define-macro="footer">
|
metal:define-macro="footer">
|
||||||
<metal:footer define-slot="footer">
|
<metal:footer define-slot="footer">
|
||||||
© Copyright <span tal:replace="view/currentYear" />,
|
© Copyright <span tal:replace="view/currentYear" />,
|
||||||
<span tal:replace="view/topMenu/copyright" />
|
cyberconcepts IT-Consulting Dr. Helmut Merz
|
||||||
(<a i18n:translate=""
|
(<a href="#"
|
||||||
tal:attributes="href string:${view/topMenu/url}/impressum">Impressum</a>)
|
tal:attributes="href string:${view/topMenu/url}/impressum">Impressum</a>)
|
||||||
<br />
|
<br />
|
||||||
Powered by
|
Powered by
|
||||||
<b><a href="http://www.wissen-statt-suchen.de">loops</a></b> ·
|
<b><a href="http://www.wissen-statt-suchen.de">loops</a></b> ·
|
|
@ -262,26 +262,10 @@ table.records th, table.records td {
|
||||||
border: 1px solid lightgrey;
|
border: 1px solid lightgrey;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.report {
|
|
||||||
position: relative;
|
|
||||||
z-index: 99;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.report th {
|
|
||||||
border-bottom: 1px solid #bbbbbb;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
table.report td {
|
table.report td {
|
||||||
border-bottom: 1px dotted #dddddd;
|
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
.report-meta table {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
dl.docutils dt {
|
dl.docutils dt {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin-top: 0.3em;
|
margin-top: 0.3em;
|
|
@ -11,10 +11,6 @@ body {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.breadcrumbs {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
width: auto;
|
width: auto;
|
||||||
margin: 0;
|
margin: 0;
|
Before Width: | Height: | Size: 580 B After Width: | Height: | Size: 580 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
@ -1,5 +1,4 @@
|
||||||
<tal:block i18n:domain="loops">
|
<tal:block i18n:domain="loops">
|
||||||
<div metal:define-macro="body">
|
|
||||||
<div metal:use-macro="views/cybertools.body_macros/body">
|
<div metal:use-macro="views/cybertools.body_macros/body">
|
||||||
|
|
||||||
|
|
||||||
|
@ -34,6 +33,12 @@
|
||||||
|
|
||||||
|
|
||||||
<metal:footer fill-slot="footer">
|
<metal:footer fill-slot="footer">
|
||||||
|
<div xtal:condition="view/editable"
|
||||||
|
tal:condition="nothing">
|
||||||
|
<span i18n:translate="">For quick creation of notes/links bookmark this link</span>:
|
||||||
|
<a href="#"
|
||||||
|
tal:attributes="href view/popupCreateObjectForm">Create loops Note</a>
|
||||||
|
</div>
|
||||||
Powered by
|
Powered by
|
||||||
<b><a href="http://loops.cy55.de">loops</a></b> ·
|
<b><a href="http://loops.cy55.de">loops</a></b> ·
|
||||||
<b><a href="http://wiki.zope.org/zope3">Zope 3</a></b> ·
|
<b><a href="http://wiki.zope.org/zope3">Zope 3</a></b> ·
|
||||||
|
@ -42,6 +47,5 @@
|
||||||
</metal:footer>
|
</metal:footer>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</tal:block>
|
</tal:block>
|
|
@ -82,15 +82,6 @@ table {
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* elements taken from blueprint (Lobo) skin */
|
|
||||||
.span-1, .span-2, .span-3, .span-4, .span-5, .span-6 {float: left;}
|
|
||||||
.span-1 {width: 105px;}
|
|
||||||
.span-2 {width: 230px;}
|
|
||||||
.span-3 {width: 355px;}
|
|
||||||
.span-4 {width: 480px;}
|
|
||||||
.span-5 {width: 605px;}
|
|
||||||
.span-6 {width: 730px;}
|
|
||||||
|
|
||||||
tr.even td {
|
tr.even td {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
@ -494,8 +485,8 @@ img.notselected {
|
||||||
/* view modes (tabs) */
|
/* view modes (tabs) */
|
||||||
|
|
||||||
ul.view-modes {
|
ul.view-modes {
|
||||||
padding: 0 0 1px 0.5em;
|
padding: 0 0 0 2em;
|
||||||
margin: 1.5em 0 0 0;
|
margin: 0.7em 0 0 0;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
border-bottom: #ccc 1px solid;
|
border-bottom: #ccc 1px solid;
|
||||||
|
@ -503,11 +494,11 @@ ul.view-modes {
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.view-modes li {
|
ul.view-modes li {
|
||||||
display: inline;
|
display: inline
|
||||||
}
|
}
|
||||||
|
|
||||||
ul.view-modes li a {
|
ul.view-modes li a {
|
||||||
padding: 3px 1.25em 3px 1.25em;
|
padding: 0.15em 1.25em 0.15em 1.25em;
|
||||||
margin: 0 0.5em 0 0;
|
margin: 0 0.5em 0 0;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
border: #ccc 1px solid;
|
border: #ccc 1px solid;
|
|
@ -10,7 +10,7 @@
|
||||||
method="post" name="listing" action="."
|
method="post" name="listing" action="."
|
||||||
tal:define="target nocall:view/target"
|
tal:define="target nocall:view/target"
|
||||||
tal:condition="python: target or items"
|
tal:condition="python: target or items"
|
||||||
tal:attributes="action view/requestUrl">
|
tal:attributes="action request/URL">
|
||||||
<input type="hidden" name="action" value="assign"
|
<input type="hidden" name="action" value="assign"
|
||||||
tal:attributes="value action" />
|
tal:attributes="value action" />
|
||||||
<table class="listing" summary="Currently assigned"
|
<table class="listing" summary="Currently assigned"
|
||||||
|
@ -45,16 +45,17 @@
|
||||||
checked python: targetToken == token" />
|
checked python: targetToken == token" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a tal:omit-tag="not:nocall:item"
|
<a href="#"
|
||||||
|
tal:omit-tag="not:nocall:item"
|
||||||
tal:content="title"
|
tal:content="title"
|
||||||
tal:define="baseUrl item/url|string:"
|
|
||||||
tal:attributes="href
|
tal:attributes="href
|
||||||
string:$baseUrl/@@SelectedManagementView.html">
|
string:${item/url|nothing}/@@SelectedManagementView.html">
|
||||||
Title
|
Title
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<a tal:condition="type"
|
<a tal:condition="type"
|
||||||
|
href="#"
|
||||||
tal:attributes="href
|
tal:attributes="href
|
||||||
string:${item/typeUrl}/@@SelectedManagementView.html"
|
string:${item/typeUrl}/@@SelectedManagementView.html"
|
||||||
tal:omit-tag="not:item/typeUrl">
|
tal:omit-tag="not:item/typeUrl">
|
||||||
|
@ -82,7 +83,7 @@
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend i18n:translate="">Create Target</legend>
|
<legend i18n:translate="">Create Target</legend>
|
||||||
<form method="post" name="listing" action="."
|
<form method="post" name="listing" action="."
|
||||||
tal:attributes="action view/requestUrl">
|
tal:attributes="action request/URL">
|
||||||
<input type="hidden" name="action" value="create" />
|
<input type="hidden" name="action" value="create" />
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span i18n:translate="">Name</span>
|
<span i18n:translate="">Name</span>
|
||||||
|
@ -113,7 +114,7 @@
|
||||||
|
|
||||||
<metal:search define-macro="search">
|
<metal:search define-macro="search">
|
||||||
<form method="post" name="listing" action="."
|
<form method="post" name="listing" action="."
|
||||||
tal:attributes="action view/requestUrl">
|
tal:attributes="action request/URL">
|
||||||
<input type="hidden" name="action" value="search" />
|
<input type="hidden" name="action" value="search" />
|
||||||
<div class="row"
|
<div class="row"
|
||||||
tal:define="searchTerm request/searchTerm | nothing;
|
tal:define="searchTerm request/searchTerm | nothing;
|
|
@ -1,13 +1,29 @@
|
||||||
# loops.browser.util
|
#
|
||||||
|
# Copyright (c) 2011 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Utilities.
|
"""
|
||||||
|
Utilities.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import re
|
import re, urllib
|
||||||
import urllib.parse
|
from zope.app.pagetemplate import ViewPageTemplateFile
|
||||||
from zope.browserpage import ViewPageTemplateFile
|
from zope.app.publisher.browser.menu import BrowserMenu
|
||||||
from zope.browsermenu.menu import BrowserMenu
|
from zope.app.publisher.interfaces.browser import IBrowserSubMenuItem
|
||||||
from zope.browsermenu.interfaces import IBrowserSubMenuItem
|
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.formlib.namedtemplate import NamedTemplateImplementation
|
from zope.formlib.namedtemplate import NamedTemplateImplementation
|
||||||
|
|
||||||
|
@ -52,4 +68,4 @@ def html_quote(text, character_entities=((u'&', u'&'), (u'<', u'<' ),
|
||||||
pattern = re.compile(r'[ /\?\+\|%]')
|
pattern = re.compile(r'[ /\?\+\|%]')
|
||||||
|
|
||||||
def normalizeForUrl(text):
|
def normalizeForUrl(text):
|
||||||
return urllib.parse.quote(pattern.sub('-', text).encode('UTF-8'))
|
return urllib.quote(pattern.sub('-', text).encode('UTF-8'))
|
|
@ -4,6 +4,8 @@ loops - Linked Objects for Organization and Processing Services
|
||||||
|
|
||||||
Automatic classification of resources.
|
Automatic classification of resources.
|
||||||
|
|
||||||
|
($Id$)
|
||||||
|
|
||||||
|
|
||||||
Setting up a loops Site and Utilities
|
Setting up a loops Site and Utilities
|
||||||
=====================================
|
=====================================
|
||||||
|
@ -37,7 +39,7 @@ from external files so we have something to work with.
|
||||||
|
|
||||||
>>> tExternalCollection = concepts['extcollection']
|
>>> tExternalCollection = concepts['extcollection']
|
||||||
>>> coll01 = addObject(concepts, Concept, 'coll01',
|
>>> coll01 = addObject(concepts, Concept, 'coll01',
|
||||||
... title='Collection One', conceptType=tExternalCollection)
|
... title=u'Collection One', conceptType=tExternalCollection)
|
||||||
>>> aColl01 = adapted(coll01)
|
>>> aColl01 = adapted(coll01)
|
||||||
>>> aColl01.baseAddress = dataDir
|
>>> aColl01.baseAddress = dataDir
|
||||||
>>> aColl01.address = ''
|
>>> aColl01.address = ''
|
||||||
|
@ -47,7 +49,7 @@ from external files so we have something to work with.
|
||||||
7
|
7
|
||||||
>>> rnames = list(sorted(resources.keys()))
|
>>> rnames = list(sorted(resources.keys()))
|
||||||
>>> rnames[0]
|
>>> rnames[0]
|
||||||
'cust_im_contract_webbg_20071015.txt'
|
u'cust_im_contract_webbg_20071015.txt'
|
||||||
|
|
||||||
|
|
||||||
Filename-based Classification
|
Filename-based Classification
|
||||||
|
@ -74,7 +76,7 @@ and follow the classifier step by step.
|
||||||
>>> from loops.classifier.interfaces import IExtractor, IAnalyzer
|
>>> from loops.classifier.interfaces import IExtractor, IAnalyzer
|
||||||
>>> infoSet = InformationSet()
|
>>> infoSet = InformationSet()
|
||||||
>>> for name in classifier.extractors.split():
|
>>> for name in classifier.extractors.split():
|
||||||
... print('extractor:', name)
|
... print 'extractor:', name
|
||||||
... extractor = component.getAdapter(adapted(r1), IExtractor, name=name)
|
... extractor = component.getAdapter(adapted(r1), IExtractor, name=name)
|
||||||
... infoSet.update(extractor.extractInformationSet())
|
... infoSet.update(extractor.extractInformationSet())
|
||||||
extractor: filename
|
extractor: filename
|
||||||
|
@ -94,32 +96,32 @@ So there seems to be something missing - we have to create concepts
|
||||||
that may be identified as being candidates for classification.
|
that may be identified as being candidates for classification.
|
||||||
|
|
||||||
>>> tInstitution = addObject(concepts, Concept, 'institution',
|
>>> tInstitution = addObject(concepts, Concept, 'institution',
|
||||||
... title='Institution', conceptType=concepts['type'])
|
... title=u'Institution', conceptType=concepts['type'])
|
||||||
>>> cust_im = addObject(concepts, Concept, 'im_editors',
|
>>> cust_im = addObject(concepts, Concept, 'im_editors',
|
||||||
... title='im Editors', conceptType=tInstitution)
|
... title=u'im Editors', conceptType=tInstitution)
|
||||||
>>> cust_mc = addObject(concepts, Concept, 'mc_consulting',
|
>>> cust_mc = addObject(concepts, Concept, 'mc_consulting',
|
||||||
... title='MC Management Consulting', conceptType=tInstitution)
|
... title=u'MC Management Consulting', conceptType=tInstitution)
|
||||||
|
|
||||||
>>> tDoctype = addObject(concepts, Concept, 'doctype',
|
>>> tDoctype = addObject(concepts, Concept, 'doctype',
|
||||||
... title='Document Type', conceptType=concepts['type'])
|
... title=u'Document Type', conceptType=concepts['type'])
|
||||||
>>> dt_note = addObject(concepts, Concept, 'dt_note',
|
>>> dt_note = addObject(concepts, Concept, 'dt_note',
|
||||||
... title='Note', conceptType=tDoctype)
|
... title=u'Note', conceptType=tDoctype)
|
||||||
>>> dt_contract = addObject(concepts, Concept, 'dt_contract',
|
>>> dt_contract = addObject(concepts, Concept, 'dt_contract',
|
||||||
... title='Contract', conceptType=tDoctype)
|
... title=u'Contract', conceptType=tDoctype)
|
||||||
|
|
||||||
>>> tPerson = concepts['person']
|
>>> tPerson = concepts['person']
|
||||||
>>> webbg = addObject(concepts, Concept, 'webbg',
|
>>> webbg = addObject(concepts, Concept, 'webbg',
|
||||||
... title='Gerald Webb', conceptType=tPerson)
|
... title=u'Gerald Webb', conceptType=tPerson)
|
||||||
>>> smitha = addObject(concepts, Concept, 'smitha',
|
>>> smitha = addObject(concepts, Concept, 'smitha',
|
||||||
... title='Angelina Smith', conceptType=tPerson)
|
... title=u'Angelina Smith', conceptType=tPerson)
|
||||||
>>> watersj = addObject(concepts, Concept, 'watersj',
|
>>> watersj = addObject(concepts, Concept, 'watersj',
|
||||||
... title='Jerry Waters', conceptType=tPerson)
|
... title=u'Jerry Waters', conceptType=tPerson)
|
||||||
>>> millerj = addObject(concepts, Concept, 'millerj',
|
>>> millerj = addObject(concepts, Concept, 'millerj',
|
||||||
... title='Jeannie Miller', conceptType=tPerson)
|
... title=u'Jeannie Miller', conceptType=tPerson)
|
||||||
|
|
||||||
>>> t.indexAll(concepts, resources)
|
>>> t.indexAll(concepts, resources)
|
||||||
|
|
||||||
>>> from zope.catalog.interfaces import ICatalog
|
>>> from zope.app.catalog.interfaces import ICatalog
|
||||||
>>> cat = component.getUtility(ICatalog)
|
>>> cat = component.getUtility(ICatalog)
|
||||||
|
|
||||||
>>> statements = analyzer.extractStatements(infoSet)
|
>>> statements = analyzer.extractStatements(infoSet)
|
||||||
|
@ -133,7 +135,7 @@ So we are now ready to have the whole stuff run in one call.
|
||||||
Classifier fileclassifier: Assigning: ...
|
Classifier fileclassifier: Assigning: ...
|
||||||
|
|
||||||
>>> list(sorted([c.title for c in r1.getConcepts()]))
|
>>> list(sorted([c.title for c in r1.getConcepts()]))
|
||||||
['Collection One', 'Contract', 'External File', 'Gerald Webb', 'im Editors']
|
[u'Collection One', u'Contract', u'External File', u'Gerald Webb', u'im Editors']
|
||||||
|
|
||||||
>>> for name in rnames[1:]:
|
>>> for name in rnames[1:]:
|
||||||
... classifier.process(resources[name])
|
... classifier.process(resources[name])
|
|
@ -1,6 +1,23 @@
|
||||||
# looops.classifier.base
|
#
|
||||||
|
# Copyright (c) 2015 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Adapters and others classes for analyzing resources.
|
"""
|
||||||
|
Adapters and others classes for analyzing resources.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from itertools import tee
|
from itertools import tee
|
||||||
|
@ -9,7 +26,7 @@ from zope.cachedescriptors.property import Lazy
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.event import notify
|
from zope.event import notify
|
||||||
from zope.interface import implementer
|
from zope.interface import implements
|
||||||
from zope.traversing.api import getName, getParent
|
from zope.traversing.api import getName, getParent
|
||||||
from cybertools.typology.interfaces import IType
|
from cybertools.typology.interfaces import IType
|
||||||
|
|
||||||
|
@ -27,11 +44,11 @@ logger = getLogger('Classifier')
|
||||||
TypeInterfaceSourceList.typeInterfaces += (IClassifier,)
|
TypeInterfaceSourceList.typeInterfaces += (IClassifier,)
|
||||||
|
|
||||||
|
|
||||||
@implementer(IClassifier)
|
|
||||||
class Classifier(AdapterBase):
|
class Classifier(AdapterBase):
|
||||||
""" A concept adapter for analyzing resources.
|
""" A concept adapter for analyzing resources.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
implements(IClassifier)
|
||||||
adapts(IConcept)
|
adapts(IConcept)
|
||||||
|
|
||||||
_contextAttributes = list(IClassifier) + list(IConcept)
|
_contextAttributes = list(IClassifier) + list(IConcept)
|
||||||
|
@ -95,9 +112,9 @@ class Classifier(AdapterBase):
|
||||||
logger.info(u'%s: %s' % (getName(self.context), message))
|
logger.info(u'%s: %s' % (getName(self.context), message))
|
||||||
|
|
||||||
|
|
||||||
@implementer(IExtractor)
|
|
||||||
class Extractor(object):
|
class Extractor(object):
|
||||||
|
|
||||||
|
implements(IExtractor)
|
||||||
adapts(IResource)
|
adapts(IResource)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
|
@ -107,9 +124,9 @@ class Extractor(object):
|
||||||
return InformationSet()
|
return InformationSet()
|
||||||
|
|
||||||
|
|
||||||
@implementer(IAnalyzer)
|
|
||||||
class Analyzer(object):
|
class Analyzer(object):
|
||||||
|
|
||||||
|
implements(IAnalyzer)
|
||||||
adapts(IClassifier)
|
adapts(IClassifier)
|
||||||
|
|
||||||
def __init__(self, context):
|
def __init__(self, context):
|
||||||
|
@ -130,15 +147,15 @@ class Analyzer(object):
|
||||||
return r1
|
return r1
|
||||||
|
|
||||||
|
|
||||||
@implementer(IInformationSet)
|
|
||||||
class InformationSet(dict):
|
class InformationSet(dict):
|
||||||
|
|
||||||
pass
|
implements(IInformationSet)
|
||||||
|
|
||||||
|
|
||||||
@implementer(IStatement)
|
|
||||||
class Statement(object):
|
class Statement(object):
|
||||||
|
|
||||||
|
implements(IStatement)
|
||||||
|
|
||||||
def __init__(self, object=None, predicate=None, subject=None, relevance=100):
|
def __init__(self, object=None, predicate=None, subject=None, relevance=100):
|
||||||
self.subject = subject
|
self.subject = subject
|
||||||
self.predicate = predicate
|
self.predicate = predicate
|
|
@ -1,11 +1,30 @@
|
||||||
# loops.classifier.sample
|
#
|
||||||
|
# Copyright (c) 2007 Helmut Merz helmutm@cy55.de
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
|
||||||
""" Sample classifier implementation.
|
"""
|
||||||
|
Sample classifier implementation.
|
||||||
|
|
||||||
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from zope import component
|
from zope import component
|
||||||
|
from zope.app.catalog.interfaces import ICatalog
|
||||||
from zope.cachedescriptors.property import Lazy
|
from zope.cachedescriptors.property import Lazy
|
||||||
from zope.catalog.interfaces import ICatalog
|
|
||||||
from zope.component import adapts
|
from zope.component import adapts
|
||||||
from zope.traversing.api import getName
|
from zope.traversing.api import getName
|
||||||
|
|