├── .gitignore ├── MANIFEST.in ├── README.md ├── examples ├── simple-blog │ ├── README.md │ ├── admin.py │ ├── app.py │ └── model.py └── simplest │ ├── README.md │ └── simplest.py ├── requirements.txt ├── setup.py └── shelf ├── __init__.py ├── admin ├── .#view.py ├── __init__.py ├── actions.py ├── base.py ├── field.py ├── form.py ├── view.py └── widget.py ├── base.py ├── plugins ├── __init__.py ├── analytics │ └── __init__.py ├── dashboard │ ├── __init__.py │ ├── provider.py │ ├── static │ │ ├── dashboard.css │ │ ├── masonry.min.js │ │ ├── morris.css │ │ ├── morris.min.js │ │ └── raphael-min.js │ ├── templates │ │ ├── bar.html │ │ ├── dashboard.html │ │ ├── donut.html │ │ ├── evolution.html │ │ ├── picture-text.html │ │ └── simple-text.html │ └── widget.py ├── i18n │ ├── __init__.py │ └── templates │ │ └── localized-widget.html ├── library │ ├── __init__.py │ └── templates │ │ ├── shelf-field-file.html │ │ ├── shelf-field-picture.html │ │ ├── shelf-library-field-tail.html │ │ ├── shelf-library-icon-list.html │ │ ├── shelf-library-list.html │ │ ├── shelf-library-modal-icon-list.html │ │ ├── shelf-library-modal-list.html │ │ └── shelf-library-upload.html ├── order │ ├── __init__.py │ └── templates │ │ ├── ordering-inline-field-list.html │ │ ├── ordering-inline-form.html │ │ ├── ordering-inline-list-base.html │ │ └── ordering-inline-tail.html ├── page │ ├── __init__.py │ └── templates │ │ ├── page-admin-edit.html │ │ └── page-admin-list.html ├── preview │ ├── __init__.py │ └── templates │ │ └── preview_button.html ├── slider │ ├── __init__.py │ └── templates │ │ └── slider-field.html ├── tags │ └── __init__.py ├── workflow │ ├── __init__.py │ └── templates │ │ ├── js.html │ │ └── workflow-button.html └── wysiwyg │ ├── __init__.py │ ├── static │ └── tinymce │ │ ├── jquery.tinymce.min.js │ │ ├── langs │ │ └── readme.md │ │ ├── license.txt │ │ ├── plugins │ │ ├── advlist │ │ │ └── plugin.min.js │ │ ├── anchor │ │ │ └── plugin.min.js │ │ ├── autolink │ │ │ └── plugin.min.js │ │ ├── autoresize │ │ │ └── plugin.min.js │ │ ├── autosave │ │ │ └── plugin.min.js │ │ ├── bbcode │ │ │ └── plugin.min.js │ │ ├── charmap │ │ │ └── plugin.min.js │ │ ├── code │ │ │ └── plugin.min.js │ │ ├── colorpicker │ │ │ └── plugin.min.js │ │ ├── contextmenu │ │ │ └── plugin.min.js │ │ ├── directionality │ │ │ └── plugin.min.js │ │ ├── emoticons │ │ │ ├── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-foot-in-mouth.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ └── smiley-yell.gif │ │ │ └── plugin.min.js │ │ ├── example │ │ │ ├── dialog.html │ │ │ └── plugin.min.js │ │ ├── example_dependency │ │ │ └── plugin.min.js │ │ ├── fullpage │ │ │ └── plugin.min.js │ │ ├── fullscreen │ │ │ └── plugin.min.js │ │ ├── hr │ │ │ └── plugin.min.js │ │ ├── image │ │ │ └── plugin.min.js │ │ ├── importcss │ │ │ └── plugin.min.js │ │ ├── insertdatetime │ │ │ └── plugin.min.js │ │ ├── layer │ │ │ └── plugin.min.js │ │ ├── legacyoutput │ │ │ └── plugin.min.js │ │ ├── link │ │ │ └── plugin.min.js │ │ ├── lists │ │ │ └── plugin.min.js │ │ ├── media │ │ │ ├── moxieplayer.swf │ │ │ └── plugin.min.js │ │ ├── nonbreaking │ │ │ └── plugin.min.js │ │ ├── noneditable │ │ │ └── plugin.min.js │ │ ├── pagebreak │ │ │ └── plugin.min.js │ │ ├── paste │ │ │ └── plugin.min.js │ │ ├── preview │ │ │ └── plugin.min.js │ │ ├── print │ │ │ └── plugin.min.js │ │ ├── save │ │ │ └── plugin.min.js │ │ ├── searchreplace │ │ │ └── plugin.min.js │ │ ├── spellchecker │ │ │ └── plugin.min.js │ │ ├── tabfocus │ │ │ └── plugin.min.js │ │ ├── table │ │ │ └── plugin.min.js │ │ ├── template │ │ │ └── plugin.min.js │ │ ├── textcolor │ │ │ └── plugin.min.js │ │ ├── textpattern │ │ │ └── plugin.min.js │ │ ├── visualblocks │ │ │ ├── css │ │ │ │ └── visualblocks.css │ │ │ └── plugin.min.js │ │ ├── visualchars │ │ │ └── plugin.min.js │ │ └── wordcount │ │ │ └── plugin.min.js │ │ ├── skins │ │ └── lightgray │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── fonts │ │ │ ├── readme.md │ │ │ ├── tinymce-small.dev.svg │ │ │ ├── tinymce-small.eot │ │ │ ├── tinymce-small.svg │ │ │ ├── tinymce-small.ttf │ │ │ ├── tinymce-small.woff │ │ │ ├── tinymce.dev.svg │ │ │ ├── tinymce.eot │ │ │ ├── tinymce.svg │ │ │ ├── tinymce.ttf │ │ │ └── tinymce.woff │ │ │ ├── img │ │ │ ├── anchor.gif │ │ │ ├── loader.gif │ │ │ ├── object.gif │ │ │ └── trans.gif │ │ │ ├── skin.ie7.min.css │ │ │ └── skin.min.css │ │ ├── themes │ │ └── modern │ │ │ └── theme.min.js │ │ └── tinymce.min.js │ └── templates │ └── wysiwyg_tail.html ├── security ├── __init__.py ├── mixin.py ├── model.py └── view.py ├── static ├── bootstrap3 │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ └── bootstrap.min.css │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ └── glyphicons-halflings-regular.woff │ └── js │ │ ├── bootstrap.js │ │ └── bootstrap.min.js ├── font-awesome │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ └── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ └── fontawesome-webfont.woff ├── jquery │ └── jquery-2.1.1.min.js ├── select2 │ └── select2-flat.css ├── shelf │ ├── css │ │ ├── login.css │ │ └── shelf.css │ ├── img │ │ ├── geometry.png │ │ ├── minishelf.png │ │ ├── missing-picture.png │ │ ├── motif_up.png │ │ ├── patch_bottom_menu.jpg │ │ ├── patch_top_menu.png │ │ └── shelf_logo.png │ └── js │ │ ├── actions.js │ │ ├── filters.js │ │ └── form.js ├── switchery │ ├── switchery.min.css │ └── switchery.min.js └── tinymce │ ├── skins │ └── lightgray │ │ ├── content.inline.min.css │ │ ├── content.min.css │ │ ├── fonts │ │ ├── tinymce-small.eot │ │ ├── tinymce-small.json │ │ ├── tinymce-small.svg │ │ ├── tinymce-small.ttf │ │ ├── tinymce-small.woff │ │ ├── tinymce.eot │ │ ├── tinymce.json │ │ ├── tinymce.svg │ │ ├── tinymce.ttf │ │ └── tinymce.woff │ │ ├── img │ │ ├── anchor.gif │ │ ├── loader.gif │ │ ├── object.gif │ │ └── trans.gif │ │ ├── skin.ie7.min.css │ │ └── skin.min.css │ └── tinymce.min.js └── templates ├── layout.html ├── shelf-security ├── _macros.html ├── base.html ├── change_password.html ├── forgot_password.html ├── login.html ├── register.html ├── reset_password.html ├── send_confirmation.html └── user_panel.html └── shelf ├── actions.html ├── base.html ├── index.html ├── lib.html ├── login └── base.html ├── model ├── create.html ├── edit.html ├── inline-field-list.html ├── inline-form-collapse.html ├── inline-form.html ├── inline-list-base.html ├── layout.html └── list.html └── static.html /.gitignore: -------------------------------------------------------------------------------- 1 | test-scripts 2 | 3 | *.py[cod] 4 | *.py~ 5 | 6 | .DS_Store 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Packages 12 | *.egg 13 | *.egg-info 14 | dist 15 | build 16 | eggs 17 | parts 18 | bin 19 | var 20 | sdist 21 | develop-eggs 22 | .installed.cfg 23 | lib 24 | lib64 25 | 26 | # Installer logs 27 | pip-log.txt 28 | 29 | # Unit test / coverage reports 30 | .coverage 31 | .tox 32 | nosetests.xml 33 | 34 | # Translations 35 | *.mo 36 | 37 | # Mr Developer 38 | .mr.developer.cfg 39 | .project 40 | .pydevproject 41 | 42 | # Virtualenv 43 | env 44 | 45 | # Vim temporary files 46 | *~ 47 | *.swp 48 | *.swo 49 | 50 | # Emacs temporary files 51 | [#]*[#] 52 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include shelf/static * 2 | recursive-include shelf/plugins/*/static * 3 | recursive-include shelf/templates * 4 | recursive-include shelf/plugins/*/templates * 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #Shelf CMS 2 | Enhancing Flask microframework with a beautiful admin and cms-like features 3 | ##Uses cases 4 | 5 | ###Dynamic website administration : 6 | Create a custom administration based on [SQLAlchemy](https://github.com/zzzeek/sqlalchemy) models. 7 | The following features are available from scratch : 8 | - Extensible user system : Registration, login, lost password, permissions 9 | - Workflow system : Draft, Review or Publish any content you want 10 | - Pages : Pages are a first-class citizen in Shelf 11 | - Media library : Pictures and files explorer 12 | 13 | ###Multilingual/International website administration : 14 | Specify any content by language or by country. 15 | ###Pure data management : 16 | Create a data managment tool like a custom CRM. 17 | The following features can be useful : 18 | - Export prefiltered data to excel format 19 | - Generate insights with an extensible dashboard system and widgets 20 | 21 | ###Simple e-commerce website : 22 | Add ecommerce functionnalities by using the [Satchless](https://github.com/mirumee/satchless) library. 23 | ##Core features list 24 | Every project using Shelf has the following features : 25 | - Extensible user system : Registration, login, lost password, permissions 26 | - SQLAlchemy models : Create, Edit, Delete, Filter, Search, Browse data 27 | 28 | ##Plugins list 29 | Shelf functionnalities can be added or removed to create what only the user need. 30 | Here are the complete list : 31 | - Wysiwyg: Edit rich content with TinyMCE 32 | - Workflow: Draft, Review or Publish any content you want 33 | - Sliders: Simple edition of sliders 34 | - Orderable : Change order of content easily 35 | - Preview : See your modifications 36 | - Page : A page edition system 37 | - Library : Explore your medias 38 | - l10n/i18n : Localize/Internationalize your content 39 | - Dashboard : Create a dashboard by using widgets (text, graphics) and providers (data) 40 | - Analytics : Google analytics providers for the dashboard system 41 | 42 | ##Documentation 43 | We are writing the documentation, it should be available soon. 44 | ##Examples 45 | Examples are available in the examples/ directory. 46 | ##Installation 47 | Want to try Shelf ? Install it and its dependencies with pip : 48 | ```pip install shelfcms``` 49 | ##Team 50 | [Ismael Riahi](http://zma.fr), Software development 51 | [David Duphil](http://www.davidduphil.com), Graphical Design and User Experience 52 | Both are members of the [Batiment.B](http://www.batb.fr) web agency. 53 | -------------------------------------------------------------------------------- /examples/simple-blog/README.md: -------------------------------------------------------------------------------- 1 | Blog application 2 | ==== 3 | 4 | Here we create an admin to manage posts in a blog. 5 | Posts have four columns: title, content, picture and state. 6 | Three plugins will be used: workflow, library and wysiwyg. 7 | Data will be stored in a SQLite file. 8 | Password hashes will be stored (bcrypt function). 9 | 10 | 1. Install dependancies 11 | ```pip install shelfcms``` 12 | 13 | 2. Create static/ directory 14 | ```mkdir static``` 15 | 16 | 2. Launch app.py 17 | ```python app.py``` 18 | 19 | 3. In a browser, go to http://localhost:5000/admin/ and create your account by clicking the registration link 20 | 21 | 4. Give your user superadmin, reviewer and publisher permissions 22 | ```INSERT INTO roles_users (user_id, role_id) VALUES (1, 2),(1,3),(1,4);``` 23 | 24 | 5. In a browser, go to http://localhost:5000/admin/ 25 | Login using your chosen credentials 26 | -------------------------------------------------------------------------------- /examples/simple-blog/admin.py: -------------------------------------------------------------------------------- 1 | from shelf.admin.view import SQLAModelView 2 | 3 | from shelf.plugins.library import PictureField, LibraryViewMixin 4 | from shelf.plugins.workflow import WorkflowViewMixin, StateField 5 | from shelf.plugins.wysiwyg import ClassicWysiwygField, WysiwygViewMixin 6 | 7 | class PostModelView(SQLAModelView, LibraryViewMixin, 8 | WysiwygViewMixin, WorkflowViewMixin): 9 | column_list = ('title', 'state') 10 | form_columns = ( 11 | "title", "content", "picture", "state" 12 | ) 13 | form_overrides = { 14 | "content": ClassicWysiwygField, 15 | "picture": PictureField, 16 | "state": StateField 17 | } -------------------------------------------------------------------------------- /examples/simple-blog/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | 3 | from shelf import Shelf 4 | from shelf.plugins.library import FileAdmin 5 | 6 | import admin 7 | import model 8 | 9 | app = Flask(__name__) 10 | app.debug = True 11 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///blog.db' 12 | app.config['SECRET_KEY'] = 'notasecret' 13 | app.config['SECURITY_REGISTERABLE'] = True 14 | app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt' 15 | app.config['SECURITY_PASSWORD_SALT'] = 'mysalt'#"hash_123678*", 16 | app.config['SECURITY_REGISTER_EMAIL'] = False 17 | model.db.init_app(app) 18 | model.db.app = app 19 | 20 | shlf = Shelf(app) 21 | shlf.init_db(model.db) 22 | shlf.init_admin() 23 | shlf.init_security(model.User, model.Role) 24 | shlf.load_plugins(( 25 | "shelf.plugins.wysiwyg", 26 | "shelf.plugins.workflow", 27 | "shelf.plugins.library" 28 | )) 29 | shlf.admin.add_view(admin.PostModelView(model.Post, model.db.session)) 30 | shlf.admin.add_view(FileAdmin("static/", name="Media")) 31 | shlf.setup_plugins() 32 | app.run('0.0.0.0') -------------------------------------------------------------------------------- /examples/simple-blog/model.py: -------------------------------------------------------------------------------- 1 | from flask.ext.sqlalchemy import SQLAlchemy 2 | from flask.ext.security import UserMixin, RoleMixin 3 | 4 | from shelf.plugins.library import PictureModelMixin 5 | from shelf.plugins.workflow import WorkflowModelMixin, WORKFLOW_STATES 6 | 7 | db = SQLAlchemy() 8 | 9 | roles_users = db.Table('roles_users', 10 | db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), 11 | db.Column('role_id', db.Integer(), db.ForeignKey('role.id')) 12 | ) 13 | 14 | class Role(db.Model, RoleMixin): 15 | id = db.Column(db.Integer(), primary_key=True) 16 | 17 | name = db.Column(db.String(80), unique=True) 18 | description = db.Column(db.String(255)) 19 | 20 | 21 | class User(db.Model, UserMixin): 22 | id = db.Column(db.Integer, primary_key=True) 23 | 24 | roles = db.relationship('Role', secondary=roles_users, 25 | backref=db.backref('users', lazy='dynamic')) 26 | 27 | email = db.Column(db.String(69), unique=True) 28 | password = db.Column(db.String(255)) 29 | active = db.Column(db.Boolean()) 30 | confirmed_at = db.Column(db.DateTime()) 31 | 32 | 33 | class Picture(db.Model, PictureModelMixin): 34 | id = db.Column(db.Integer, primary_key=True) 35 | 36 | path = db.Column(db.String(255)) 37 | 38 | 39 | class Post(db.Model, WorkflowModelMixin): 40 | id = db.Column(db.Integer, primary_key=True) 41 | picture_id = db.Column(db.Integer, db.ForeignKey('picture.id')) 42 | 43 | picture = db.relationship("Picture") 44 | 45 | title = db.Column(db.String(150)) 46 | content = db.Column(db.Text) 47 | state = db.Column(db.Enum(*WORKFLOW_STATES)) -------------------------------------------------------------------------------- /examples/simplest/README.md: -------------------------------------------------------------------------------- 1 | Simplest application possible 2 | ==== 3 | 4 | Here we create an admin to manage posts in a blog. 5 | Data will be stored in a SQLite file. 6 | Passwords will be stored in plain text (and you should never do that). 7 | 8 | 1. Install dependancies 9 | ```pip install shelfcms``` 10 | 11 | 2. Launch simplest.py 12 | ```python simplest.py``` 13 | 14 | 3. Create a user in the database 15 | ```sqlite3 simplest.db``` 16 | ```INSERT into user (email, password, active, confirmed_at) VALUES ("admin@shelfcms.com", "password", 1, datetime());``` 17 | 18 | 4. Give your user superadmin permission 19 | ```INSERT INTO roles_users (user_id, role_id) VALUES (1, 2);``` 20 | 21 | 5. In a browser, go to http://localhost:5000/admin/ 22 | Log using your credentials ( admin@shelfcms.com / password ) 23 | -------------------------------------------------------------------------------- /examples/simplest/simplest.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | from flask.ext.sqlalchemy import SQLAlchemy 3 | from flask.ext.security import UserMixin, RoleMixin 4 | 5 | from shelf import Shelf 6 | from shelf.admin.view import SQLAModelView 7 | 8 | 9 | app = Flask(__name__) 10 | app.debug = True 11 | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///simplest.db' 12 | app.config['SECRET_KEY'] = 'notasecret' 13 | db = SQLAlchemy(app) 14 | 15 | roles_users = db.Table('roles_users', 16 | db.Column('user_id', db.Integer(), db.ForeignKey('user.id')), 17 | db.Column('role_id', db.Integer(), db.ForeignKey('role.id')) 18 | ) 19 | 20 | class Role(db.Model, RoleMixin): 21 | id = db.Column(db.Integer(), primary_key=True) 22 | 23 | name = db.Column(db.String(80), unique=True) 24 | description = db.Column(db.String(255)) 25 | 26 | 27 | class User(db.Model, UserMixin): 28 | id = db.Column(db.Integer, primary_key=True) 29 | 30 | roles = db.relationship('Role', secondary=roles_users, 31 | backref=db.backref('users', lazy='dynamic')) 32 | 33 | email = db.Column(db.String(69), unique=True) 34 | password = db.Column(db.String(255)) 35 | active = db.Column(db.Boolean()) 36 | confirmed_at = db.Column(db.DateTime()) 37 | 38 | 39 | class Post(db.Model): 40 | id = db.Column(db.Integer, primary_key=True) 41 | 42 | title = db.Column(db.String(150)) 43 | content = db.Column(db.Text) 44 | 45 | 46 | shlf = Shelf(app) 47 | shlf.init_db(db) 48 | shlf.init_admin() 49 | shlf.init_security(User, Role) 50 | shlf.admin.add_view(SQLAModelView(Post, db.session)) 51 | 52 | app.run('0.0.0.0') -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==0.10.1 2 | Flask-Admin==1.0.8 3 | Flask-Login==0.2.11 4 | Flask-Mail==0.9.0 5 | Flask-Plugins==1.4 6 | Flask-Principal==0.4.0 7 | Flask-SQLAlchemy==1.0 8 | Flask-Security==1.7.3 9 | Flask-WTF==0.9.5 10 | Jinja2==2.7.3 11 | MarkupSafe==0.23 12 | SQLAlchemy==0.9.6 13 | -e git+git@github.com:iriahi/shelf-cms.git@8ffc09786aae3cd49125ccbf1db1a128eb80abb5#egg=ShelfCMS-new 14 | WTForms==1.0.5 15 | Werkzeug==0.9.6 16 | blinker==1.3 17 | itsdangerous==0.24 18 | passlib==1.6.2 19 | wsgiref==0.1.2 20 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='ShelfCMS', 5 | version='0.9', 6 | url='https://github.com/iriahi/shelf-cms', 7 | license='BSD', 8 | author='Ismael Riahi', 9 | author_email='ismael@batb.fr', 10 | description="""Enhancing flask microframework with beautiful admin 11 | and cms-like features""", 12 | packages=find_packages(), 13 | include_package_data=True, 14 | zip_safe=False, 15 | install_requires=[ 16 | 'flask', 17 | 'flask-admin==1.0.8', 18 | 'flask-wtf', 19 | 'flask-security', 20 | 'flask-sqlalchemy', 21 | 'wtforms<2.0', 22 | 'py-bcrypt' 23 | ] 24 | ) 25 | -------------------------------------------------------------------------------- /shelf/__init__.py: -------------------------------------------------------------------------------- 1 | from base import Shelf 2 | -------------------------------------------------------------------------------- /shelf/admin/.#view.py: -------------------------------------------------------------------------------- 1 | zma@laptop.7394:1404670703 -------------------------------------------------------------------------------- /shelf/admin/__init__.py: -------------------------------------------------------------------------------- 1 | from base import Admin 2 | -------------------------------------------------------------------------------- /shelf/admin/actions.py: -------------------------------------------------------------------------------- 1 | from flask.ext.admin import actions 2 | from flask.ext.admin.contrib.sqla.tools import get_query_for_ids 3 | from flask import request, url_for, redirect, flash 4 | 5 | 6 | class ActionsMixin(actions.ActionsMixin): 7 | def _get_action_filter_args(self): 8 | if self._filters and request.form.get('filters', None): 9 | filters = [] 10 | 11 | for n in request.form.get('filters', None).split(','): 12 | if not n.startswith('flt'): 13 | continue 14 | 15 | if "_" not in n: 16 | continue 17 | 18 | if "=" not in n: 19 | continue 20 | 21 | arg, val = n[3:].split("=", 1) 22 | pos, key = arg.split("_", 1) 23 | 24 | if key in self._filter_args: 25 | idx, flt = self._filter_args[key] 26 | 27 | value = val 28 | 29 | if flt.validate(value): 30 | filters.append((pos, (idx, flt.clean(value)))) 31 | 32 | return [v[1] for v in sorted(filters, key=lambda n: n[0])] 33 | 34 | return None 35 | 36 | def _get_action_extra_args(self): 37 | page = request.form.get('page') 38 | sort = request.form.get('sort') 39 | desc = request.form.get('desc', None, type=int) 40 | search = request.form.get('search', None) 41 | filters = self._get_action_filter_args() 42 | 43 | return page, sort, desc, search, filters 44 | 45 | def handle_action(self, return_view=None): 46 | action = request.form.get('action') 47 | ids = request.form.getlist('rowid') 48 | page, sort, sort_desc, search, filters = self._get_action_extra_args() 49 | select_all = request.form.get('select-all', 0, type=int) 50 | select_page = request.form.get('select-page', 0, type=int) 51 | 52 | if select_all: 53 | count, query = self.get_list(None, sort, sort_desc, search, filters, False, nolimit=True) 54 | elif select_page: 55 | count, query = self.get_list(page, sort, sort_desc, search, filters, False) 56 | else: 57 | query = get_query_for_ids(self.get_query(), self.model, ids) 58 | 59 | handler = self._actions_data.get(action) 60 | 61 | if handler and self.is_action_allowed(action): 62 | response = handler[0](ids, query) 63 | 64 | if response is not None: 65 | return response 66 | 67 | if not return_view: 68 | url = url_for('.' + self._default_view) 69 | else: 70 | url = url_for('.' + return_view) 71 | 72 | return redirect(url) 73 | -------------------------------------------------------------------------------- /shelf/admin/base.py: -------------------------------------------------------------------------------- 1 | import flask_admin 2 | from view import IndexView 3 | 4 | 5 | class Admin(flask_admin.Admin): 6 | """ Custom admin class """ 7 | 8 | def __init__(self, *args, **kwargs): 9 | """ Init class """ 10 | 11 | if "base_template" not in kwargs: 12 | kwargs["base_template"] = "shelf/base.html" 13 | 14 | if "index_view" not in kwargs: 15 | endpoint = kwargs['endpoint'] if 'endpoint' in kwargs else None 16 | url = kwargs['url'] if 'url' in kwargs else None 17 | kwargs["index_view"] = IndexView(endpoint=endpoint, url=url, template='shelf/index.html') 18 | 19 | self.css = [] 20 | self.js = [] 21 | 22 | self.auto_joins = [] 23 | self.filters = [] 24 | self.form = [] 25 | self.inline_form_models = [] 26 | self.list_columns = [] 27 | self.sortable_columns = [] 28 | 29 | super(Admin, self).__init__(*args, **kwargs) 30 | 31 | 32 | def add_widget(self, *args, **kwargs): 33 | self.index_view.add_widget(*args, **kwargs) 34 | -------------------------------------------------------------------------------- /shelf/admin/field.py: -------------------------------------------------------------------------------- 1 | from .widget import ShelfInlineFieldListWidget, ShelfInlineFormWidget 2 | from flask.ext.admin.contrib.sqla.fields import InlineModelFormList 3 | from flask.ext.admin.model.fields import InlineModelFormField 4 | 5 | _unset_value = object() 6 | 7 | class ShelfInlineModelFormField(InlineModelFormField): 8 | widget = ShelfInlineFormWidget() 9 | 10 | class ShelfInlineFieldList(InlineModelFormList): 11 | widget = ShelfInlineFieldListWidget() 12 | 13 | form_field_type = ShelfInlineModelFormField 14 | 15 | def process(self, formdata, data=_unset_value): 16 | res = super(ShelfInlineFieldList, self).process(formdata, data) 17 | titles = [obj.get_title() for obj in data] 18 | for i in range(len(self.entries)): 19 | f = self.entries[i] 20 | try: 21 | title = titles[i] 22 | except IndexError: 23 | pass 24 | f.label = title -------------------------------------------------------------------------------- /shelf/admin/form.py: -------------------------------------------------------------------------------- 1 | from flask.ext.admin.contrib.sqla import form 2 | from field import ShelfInlineFieldList 3 | from shelf.plugins.order import OrderingInlineFieldList 4 | 5 | class ModelConverter(form.AdminModelConverter): 6 | pass 7 | '''def convert(self, model, mapper, prop, field_args, hidden_pk): 8 | res = super(ModelConverter, self).convert(model, mapper, prop, field_args, hidden_pk) 9 | if field_args and "is_order" in field_args: 10 | del field_args["is_order"] 11 | res.short_name = "_is_order" 12 | print res 13 | return res''' 14 | 15 | class InlineModelConverter(form.InlineModelConverter): 16 | inline_field_list_type = OrderingInlineFieldList -------------------------------------------------------------------------------- /shelf/admin/widget.py: -------------------------------------------------------------------------------- 1 | from flask.ext.admin.form import RenderTemplateWidget 2 | 3 | class ShelfInlineFieldListWidget(RenderTemplateWidget): 4 | def __init__(self): 5 | super(ShelfInlineFieldListWidget, self).__init__('shelf/model/inline-field-list.html') 6 | 7 | class ShelfInlineFormWidget(RenderTemplateWidget): 8 | def __init__(self): 9 | super(ShelfInlineFormWidget, self).__init__('shelf/model/inline-form.html') 10 | 11 | def __call__(self, field, **kwargs): 12 | kwargs.setdefault('form_opts', getattr(field, 'form_opts', None)) 13 | return super(ShelfInlineFormWidget, self).__call__(field, **kwargs) 14 | -------------------------------------------------------------------------------- /shelf/plugins/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/__init__.py -------------------------------------------------------------------------------- /shelf/plugins/dashboard/__init__.py: -------------------------------------------------------------------------------- 1 | from flask_admin.base import AdminIndexView, expose 2 | from flask import Blueprint 3 | from shelf.security.mixin import LoginMixin 4 | 5 | config = { 6 | "name": "Dashboard", 7 | "description": "Dashboard-like view using tiles containing text and chart." 8 | } 9 | 10 | class DashboardView(LoginMixin, AdminIndexView): 11 | widgets = [] 12 | 13 | def __init__(self, *args, **kwargs): 14 | if "template" not in kwargs: 15 | kwargs["template"] = "dashboard.html" 16 | return super(DashboardView, self).__init__(*args, **kwargs) 17 | 18 | def add_widget(self, view, provider=None): 19 | if not self.widgets: 20 | self.widgets = [] 21 | if provider: 22 | view.provider = provider 23 | self.widgets.append(view) 24 | 25 | @expose("/") 26 | def index(self): 27 | return self.render(self._template, widgets=[w.render() for w in self.widgets]) 28 | 29 | class Dashboard: 30 | def __init__(self): 31 | self.config = config 32 | 33 | def init_app(self, app): 34 | self.bp = Blueprint("dashboard", __name__, url_prefix="/dashboard", 35 | static_folder="static", template_folder="templates") 36 | app.register_blueprint(self.bp) -------------------------------------------------------------------------------- /shelf/plugins/dashboard/provider.py: -------------------------------------------------------------------------------- 1 | class BaseProvider: 2 | def compute(): 3 | raise NotImplementedError 4 | 5 | 6 | class TextProvider(BaseProvider): 7 | def get_data(self): 8 | raise NotImplementedError 9 | 10 | def get_legend(self): 11 | raise NotImplementedError 12 | 13 | def compute(self): 14 | return { 15 | "data": self.get_data(), 16 | "legend": self.get_legend() 17 | } 18 | 19 | 20 | class PictureTextProvider(TextProvider): 21 | def get_picture(self): 22 | raise NotImplementedError 23 | 24 | def compute(self): 25 | return { 26 | "data": self.get_data(), 27 | "legend": self.get_legend(), 28 | "picture": self.get_picture() 29 | } 30 | 31 | 32 | class DonutProvider(BaseProvider): 33 | def get_legend(self): 34 | raise NotImplementedError 35 | 36 | def get_points(self): 37 | raise NotImplementedError 38 | 39 | def compute(self): 40 | return { 41 | "legend": self.get_legend(), 42 | "points": self.get_points() 43 | } 44 | 45 | 46 | class EvolutionProvider(BaseProvider): 47 | def get_data(self): 48 | raise NotImplementedError 49 | 50 | def get_legend(self): 51 | raise NotImplementedError 52 | 53 | def get_points(self): 54 | raise NotImplementedError 55 | 56 | def compute(self): 57 | return { 58 | "data": self.get_data(), 59 | "legend": self.get_legend(), 60 | "points": self.get_points() 61 | } 62 | 63 | class BarProvider(BaseProvider): 64 | def get_points(self): 65 | raise NotImplementedError 66 | 67 | def get_max(self): 68 | raise NotImplementedError 69 | 70 | def get_total(self): 71 | raise NotImplementedError 72 | 73 | def compute(self): 74 | return { 75 | "points": self.get_points(), 76 | "max": self.get_max(), 77 | "total": self.get_total() 78 | } 79 | 80 | -------------------------------------------------------------------------------- /shelf/plugins/dashboard/static/dashboard.css: -------------------------------------------------------------------------------- 1 | #wrap > .contain { 2 | margin-top: 50px; 3 | margin-left: auto; 4 | margin-right: auto; 5 | padding: 50px 0; 6 | } 7 | 8 | .progress { 9 | box-shadow: none !important; 10 | -webkit-box-shadow: none !important; 11 | -moz-box-shadow: none !important; 12 | } 13 | 14 | .widget { 15 | padding: 18px; 16 | font-family: 'Open Sans', sans-serif; 17 | color: #4c4c4c; 18 | } 19 | 20 | .widget .title { 21 | font-size: 12px; 22 | } 23 | 24 | .widget.picture .data { 25 | font-size: 20px; 26 | } 27 | 28 | .widget.picture .legend { 29 | font-size: 12px; 30 | } 31 | 32 | .widget.text .data { 33 | font-size: 30px; 34 | } 35 | 36 | .widget.text .legend { 37 | font-size: 12px; 38 | } 39 | 40 | .widget.text .legend .value { 41 | color: #77af96; 42 | } 43 | 44 | .widget.text .legend .value-bad { 45 | color: #ff4262; 46 | } 47 | 48 | .text p { 49 | font-size: 12px; 50 | font-family: "Open Sans"; 51 | color: #505050; 52 | } 53 | 54 | .text p span { 55 | font-weight: 300; 56 | } 57 | 58 | .text p.product { 59 | font-weight: 700; 60 | } 61 | 62 | .text p.medium { 63 | font-weight: 700; 64 | } 65 | 66 | .text p.message { 67 | font-style: italic; 68 | } 69 | 70 | .operation-name { 71 | background-color: #292a2d; 72 | color: white; 73 | font-family: "Open Sans"; 74 | font-weight: 300; 75 | } 76 | 77 | .operation-name p { 78 | color: white; 79 | font-family: "Open Sans"; 80 | font-weight: 300; 81 | } 82 | 83 | .operation-name b { 84 | font-weight: 700; 85 | } 86 | 87 | .widget { z-index: 0; } 88 | .widget:hover { z-index: 10; } -------------------------------------------------------------------------------- /shelf/plugins/dashboard/static/morris.css: -------------------------------------------------------------------------------- 1 | .morris-hover{position:absolute;z-index:1000} 2 | .morris-hover.morris-default-style{border-radius:10px;padding:6px;color:#666;background:rgba(255,255,255,0.8);border:solid 2px rgba(230,230,230,0.8);font-family:'Open Sans';font-size:12px;text-align:center} 3 | .morris-hover.morris-default-style .morris-hover-row-label{font-weight:normal;margin:0.25em 0} 4 | .morris-hover.morris-default-style .morris-hover-point{white-space:nowrap;margin:0.1em 0} -------------------------------------------------------------------------------- /shelf/plugins/dashboard/templates/bar.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /shelf/plugins/dashboard/templates/dashboard.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/master.html' %} 2 | 3 | {% block head_css %} 4 | {{ super() }} 5 | 9 | 10 | 11 | {% endblock %} 12 | 13 | {% block superbody %} 14 |{{ lang.upper() }}
75 |]*>/gi,"[quote]"),e(/<\/blockquote>/gi,"[/quote]"),e(/'),c=e.dom.create("div",null,r);t=c.lastChild;)e.dom.insertAfter(t,s[i]);e.dom.remove(s[i])}else for(s=e.dom.select("span.mce-nbsp",l),i=s.length-1;i>=0;i--)e.dom.remove(s[i],1);m.moveToBookmark(d)}function t(){var a=this;e.on("VisualChars",function(e){a.active(e.state)})}var n,o=this;e.addCommand("mceVisualChars",a),e.addButton("visualchars",{title:"Show invisible characters",cmd:"mceVisualChars",onPostRender:t}),e.addMenuItem("visualchars",{text:"Show invisible characters",cmd:"mceVisualChars",onPostRender:t,selectable:!0,context:"view",prependToContext:!0}),e.on("beforegetcontent",function(e){n&&"raw"!=e.format&&!e.draft&&(n=!0,a(!1))})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/wordcount/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("wordcount",function(e){function t(){e.theme.panel.find("#wordcount").text(["Words: {0}",a.getCount()])}var n,o,a=this;n=e.getParam("wordcount_countregex",/[\w\u2019\x27\-\u00C0-\u1FFF]+/g),o=e.getParam("wordcount_cleanregex",/[0-9.(),;:!?%#$?\x27\x22_+=\\\/\-]*/g),e.on("init",function(){var n=e.theme.panel&&e.theme.panel.find("#statusbar")[0];n&&window.setTimeout(function(){n.insert({type:"label",name:"wordcount",text:["Words: {0}",a.getCount()],classes:"wordcount",disabled:e.settings.readonly},0),e.on("setcontent beforeaddundo",t),e.on("keyup",function(e){32==e.keyCode&&t()})},0)}),a.getCount=function(){var t=e.getContent({format:"raw"}),a=0;if(t){t=t.replace(/\.\.\./g," "),t=t.replace(/<.[^<>]*?>/g," ").replace(/ | /gi," "),t=t.replace(/(\w+)(?[a-z0-9]+;)+(\w+)/i,"$1$3").replace(/&.+?;/g," "),t=t.replace(o,"");var r=t.match(n);r&&(a=r.length)}return a}}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/content.inline.min.css: -------------------------------------------------------------------------------- 1 | .mce-object{border:1px dotted #3A3A3A;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0px}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333} -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/content.min.css: -------------------------------------------------------------------------------- 1 | body{background-color:#FFFFFF;color:#000000;font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px;scrollbar-3dlight-color:#F0F0EE;scrollbar-arrow-color:#676662;scrollbar-base-color:#F0F0EE;scrollbar-darkshadow-color:#DDDDDD;scrollbar-face-color:#E0E0DD;scrollbar-highlight-color:#F0F0EE;scrollbar-shadow-color:#F0F0EE;scrollbar-track-color:#F5F5F5}td,th{font-family:Verdana,Arial,Helvetica,sans-serif;font-size:11px}.mce-object{border:1px dotted #3A3A3A;background:#d5d5d5 url(img/object.gif) no-repeat center}.mce-pagebreak{cursor:default;display:block;border:0;width:100%;height:5px;border:1px dashed #666;margin-top:15px;page-break-before:always}@media print{.mce-pagebreak{border:0px}}.mce-item-anchor{cursor:default;display:inline-block;-webkit-user-select:all;-webkit-user-modify:read-only;-moz-user-select:all;-moz-user-modify:read-only;user-select:all;user-modify:read-only;width:9px !important;height:9px !important;border:1px dotted #3A3A3A;background:#d5d5d5 url(img/anchor.gif) no-repeat center}.mce-nbsp{background:#AAA}hr{cursor:default}.mce-match-marker{background:#AAA;color:#fff}.mce-match-marker-selected{background:#3399ff;color:#fff}.mce-spellchecker-word{border-bottom:2px solid #F00;cursor:default}.mce-spellchecker-grammar{border-bottom:2px solid #008000;cursor:default}.mce-item-table,.mce-item-table td,.mce-item-table th,.mce-item-table caption{border:1px dashed #BBB}td.mce-item-selected,th.mce-item-selected{background-color:#3399ff !important}.mce-edit-focus{outline:1px dotted #333} -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/readme.md: -------------------------------------------------------------------------------- 1 | Icons are generated and provided by the http://icomoon.io service. 2 | -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.eot -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.ttf -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce-small.woff -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.eot -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.ttf -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/fonts/tinymce.woff -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/anchor.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/anchor.gif -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/loader.gif -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/object.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/object.gif -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/trans.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/skins/lightgray/img/trans.gif -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/templates/wysiwyg_tail.html: -------------------------------------------------------------------------------- 1 | 2 | 46 | -------------------------------------------------------------------------------- /shelf/security/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/security/__init__.py -------------------------------------------------------------------------------- /shelf/security/mixin.py: -------------------------------------------------------------------------------- 1 | from flask_security import url_for_security, current_user 2 | from flask import redirect, url_for, abort 3 | 4 | class LoginMixin: 5 | def _handle_view(self, name, **kwargs): 6 | if not self.is_accessible() and current_user.is_anonymous(): 7 | return redirect(url_for_security('login', next=url_for(".%s" % name))) 8 | if not self.is_accessible() and current_user.is_authenticated(): 9 | abort(403) 10 | 11 | def is_accessible(self): 12 | return current_user.is_authenticated() and \ 13 | (current_user.has_role('admin') or \ 14 | current_user.has_role('superadmin')) 15 | 16 | 17 | class UserPanelMixin: 18 | def additionnal_context(self): 19 | return dict(current_user=current_user) -------------------------------------------------------------------------------- /shelf/security/model.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/security/model.py -------------------------------------------------------------------------------- /shelf/security/view.py: -------------------------------------------------------------------------------- 1 | from flask_security import url_for_security, current_user 2 | from shelf.admin.view import SQLAModelView 3 | from flask import render_template, request, redirect, url_for 4 | 5 | class UserModelView(SQLAModelView): 6 | default_forbidden_columns = ("password", "confirmed_at") 7 | can_edit = True 8 | can_create = False 9 | can_delete = False 10 | 11 | def __init__(self, *args, **kwargs): 12 | self.forbidden_columns = self.default_forbidden_columns 13 | super(UserModelView, self).__init__(*args, **kwargs) 14 | 15 | def edit_form(self, obj): 16 | form = super(SQLAModelView, self).edit_form(obj) 17 | if not current_user.has_role('superadmin'): 18 | delattr(form, "roles") 19 | delattr(form, "active") 20 | return form 21 | 22 | def scaffold_list_columns(self): 23 | columns = super(SQLAModelView, self).scaffold_list_columns() 24 | for column in self.forbidden_columns: 25 | columns.remove(column) 26 | return columns 27 | 28 | def scaffold_form(self): 29 | form = super(SQLAModelView, self).scaffold_form() 30 | for column in self.forbidden_columns: 31 | delattr(form, column) 32 | delattr(form, "email") 33 | return form 34 | 35 | def is_accessible(self): 36 | if request.endpoint == "userview.edit_view" and \ 37 | int(request.args['id']) == current_user.id: 38 | return current_user.is_authenticated() and \ 39 | (current_user.has_role('admin') or \ 40 | current_user.has_role('superadmin')) 41 | return current_user.is_authenticated() and \ 42 | current_user.has_role('superadmin') 43 | -------------------------------------------------------------------------------- /shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/bootstrap3/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /shelf/static/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /shelf/static/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /shelf/static/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /shelf/static/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /shelf/static/select2/select2-flat.css: -------------------------------------------------------------------------------- 1 | .select2-container .select2-choice { 2 | height: 34px; 3 | -webkit-box-shadow: none; 4 | -moz-box-shadow: none; 5 | box-shadow: none; 6 | background-color: #fff; 7 | background-image: none; 8 | background: #fff; 9 | } 10 | 11 | .select2-container .select2-choice .select2-chosen { margin-top: 4px } 12 | .select2-container .select2-choice abbr { top: 13px } 13 | .select2-container .select2-choice, 14 | .select2-container .select2-choice .select2-arrow { 15 | -webkit-border-radius: 0; 16 | border-radius: 0; 17 | border-color: #ccc; 18 | } 19 | 20 | .select2-container .select2-choice .select2-arrow { 21 | background-color: #fafafa; 22 | background-image: none; 23 | background: #fafafa; 24 | /*width: 22px;*/ 25 | } 26 | 27 | .select2-container .select2-choice .select2-arrow b>span { margin: 4px 0 0 6px } 28 | .select2-container.select2-container-active .select2-choice { border-color: #91acce } 29 | .select2-container.select2-dropdown-open .select2-choice { border-bottom-color: #ccc } 30 | .select2-drop { 31 | -webkit-border-radius: 0 !important; 32 | border-radius: 0 !important; 33 | } 34 | 35 | .select2-drop:not(.select2-drop-above) { margin-top: -3px } 36 | .select2-drop .select2-results { max-height: 300px } 37 | .select2-drop .select2-results li { 38 | line-height: inherit; 39 | margin: 0; 40 | padding: 0; 41 | } 42 | 43 | .select2-search { margin: 4px 0 } 44 | .select2-search input, 45 | .select2-search input:focus { 46 | background-color: #fff; 47 | background-image: none; 48 | background: #fff; 49 | -webkit-box-shadow: none; 50 | -moz-box-shadow: none; 51 | box-shadow: none; 52 | border: none; 53 | } 54 | 55 | .select2-container.form-control { 56 | border: none; 57 | -webkit-box-shadow: none; 58 | -moz-box-shadow: none; 59 | box-shadow: none; 60 | padding: 0; 61 | } -------------------------------------------------------------------------------- /shelf/static/shelf/css/login.css: -------------------------------------------------------------------------------- 1 | input, a, label, h1, button { 2 | font-family: 'Open Sans', sans-serif !important; 3 | font-weight: 300 !important; 4 | border-radius: 0 !important; 5 | font-size: 12px; 6 | } 7 | 8 | input { 9 | border: 0px none !important; 10 | } 11 | 12 | span.input-group-addon { 13 | border-radius: 0 !important; 14 | background-color: white; 15 | border: 0px none !important; 16 | -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); 17 | box-shadow: inset 0 1px 1px rgba(0,0,0,0.075); 18 | } 19 | 20 | input[type=password] { 21 | margin-top: 3px !important; 22 | } 23 | 24 | input#remember { 25 | margin-top: 12px !important; 26 | 27 | } 28 | 29 | textarea:focus, input[type="text"]:focus, input[type="password"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="date"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, input[type="number"]:focus, input[type="email"]:focus, input[type="url"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="color"]:focus, .uneditable-input:focus { 30 | border-color: #ccc; 31 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 8px rgba(0, 0, 0, 0.4); 32 | outline: 0 none; 33 | } 34 | 35 | i { 36 | width: 11px; 37 | } 38 | 39 | a { 40 | color: #f14461 !important; 41 | } 42 | 43 | h1 { 44 | margin-top: 5px !important; 45 | } 46 | 47 | .alert 48 | { 49 | position: fixed; 50 | right: 0px; 51 | left: 0px; 52 | bottom: 0px; 53 | } 54 | 55 | input#submit { 56 | width: 100%; 57 | margin-top: 10px !important; 58 | background-color: #ff4262 !important; 59 | color: #fff !important; 60 | border: 0px none !important; 61 | } 62 | 63 | .has-error input { 64 | border: 1px solid rgba(209, 64, 64, 0.9) !important; 65 | } -------------------------------------------------------------------------------- /shelf/static/shelf/img/geometry.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/geometry.png -------------------------------------------------------------------------------- /shelf/static/shelf/img/minishelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/minishelf.png -------------------------------------------------------------------------------- /shelf/static/shelf/img/missing-picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/missing-picture.png -------------------------------------------------------------------------------- /shelf/static/shelf/img/motif_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/motif_up.png -------------------------------------------------------------------------------- /shelf/static/shelf/img/patch_bottom_menu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/patch_bottom_menu.jpg -------------------------------------------------------------------------------- /shelf/static/shelf/img/patch_top_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/patch_top_menu.png -------------------------------------------------------------------------------- /shelf/static/shelf/img/shelf_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/static/shelf/img/shelf_logo.png -------------------------------------------------------------------------------- /shelf/static/shelf/js/filters.js: -------------------------------------------------------------------------------- 1 | var AdminFilters = function(element, filtersElement, filterGroups) { 2 | var $root = $(element); 3 | var $container = $root; 4 | var lastCount = 0; 5 | 6 | function getCount(name) { 7 | var idx = name.indexOf('_'); 8 | 9 | if (idx === -1) { 10 | return 0; 11 | } 12 | 13 | return parseInt(name.substr(3, idx - 3), 10); 14 | } 15 | 16 | function makeName(name) { 17 | var result = 'flt' + lastCount + '_' + name; 18 | lastCount += 1; 19 | return result; 20 | } 21 | 22 | function changeOperation() { 23 | var $row = $(this).closest('.row'); 24 | var $el = $('.filter-val:input', $row); 25 | var count = getCount($el.attr('name')); 26 | $el.attr('name', 'flt' + count + '_' + $(this).val()); 27 | $('button', $root).show(); 28 | } 29 | 30 | function removeFilter() { 31 | $(this).closest('.row').remove(); 32 | $('button', $root).show(); 33 | 34 | return false; 35 | } 36 | 37 | function addFilter(name, subfilters) { 38 | var $el = $('').appendTo($container); 39 | 40 | // Filter list 41 | $el.append($('') 42 | .append($(' ')) 43 | .append(' ') 44 | .append(name) 45 | .click(removeFilter) 46 | ); 47 | 48 | // Filter type 49 | var $select = $('') 50 | .change(changeOperation); 51 | 52 | $(subfilters).each(function() { 53 | $select.append($('').attr('value', this.arg).text(this.operation)); 54 | }); 55 | 56 | $el.append($select); 57 | 58 | $select.select2({width: 'resolve'}); 59 | 60 | // Input 61 | var filter = subfilters[0]; 62 | 63 | var $field; 64 | 65 | if (filter.options) { 66 | $field = $('') 67 | .attr('name', makeName(filter.arg)); 68 | 69 | $(filter.options).each(function() { 70 | $field.append($('') 71 | .val(this[0]).text(this[1])); 72 | }); 73 | 74 | $el.append($('
/gi,"\n"),e(/
/gi,"\n"),e(/
/gi,"\n"),e(//gi,""),e(/<\/p>/gi,"\n"),e(/ |\u00a0/gi," "),e(/"/gi,'"'),e(/</gi,"<"),e(/>/gi,">"),e(/&/gi,"&"),o},_punbb_bbcode2html:function(o){function e(e,t){o=o.replace(e,t)}return o=tinymce.trim(o),e(/\n/gi,"
"),e(/\[b\]/gi,""),e(/\[\/b\]/gi,""),e(/\[i\]/gi,""),e(/\[\/i\]/gi,""),e(/\[u\]/gi,""),e(/\[\/u\]/gi,""),e(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,'$2'),e(/\[url\](.*?)\[\/url\]/gi,'$1'),e(/\[img\](.*?)\[\/img\]/gi,''),e(/\[color=(.*?)\](.*?)\[\/color\]/gi,'$2'),e(/\[code\](.*?)\[\/code\]/gi,'$1 '),e(/\[quote.*?\](.*?)\[\/quote\]/gi,'$1 '),o}}),tinymce.PluginManager.add("bbcode",tinymce.plugins.BBCodePlugin)}(); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/code/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("code",function(e){function o(){var o=e.windowManager.open({title:"Source code",body:{type:"textbox",name:"code",multiline:!0,minWidth:e.getParam("code_dialog_width",600),minHeight:e.getParam("code_dialog_height",Math.min(tinymce.DOM.getViewPort().h-200,500)),spellcheck:!1,style:"direction: ltr; text-align: left"},onSubmit:function(o){e.focus(),e.undoManager.transact(function(){e.setContent(o.data.code)}),e.selection.setCursorLocation(),e.nodeChanged()}});o.find("#code").value(e.getContent({source_view:!0}))}e.addCommand("mceCodeEditor",o),e.addButton("code",{icon:"code",tooltip:"Source code",onclick:o}),e.addMenuItem("code",{icon:"code",text:"Source code",context:"tools",onclick:o})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/colorpicker/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("colorpicker",function(e){function n(n,a){function i(e){var n=new tinymce.util.Color(e),a=n.toRgb();l.fromJSON({r:a.r,g:a.g,b:a.b,hex:n.toHex().substr(1)}),t(n.toHex())}function t(e){l.find("#preview")[0].getEl().style.background=e}var l=e.windowManager.open({title:"Color",items:{type:"container",layout:"flex",direction:"row",align:"stretch",padding:5,spacing:10,items:[{type:"colorpicker",value:a,onchange:function(){var e=this.rgb();l&&(l.find("#r").value(e.r),l.find("#g").value(e.g),l.find("#b").value(e.b),l.find("#hex").value(this.value().substr(1)),t(this.value()))}},{type:"form",padding:0,labelGap:5,defaults:{type:"textbox",size:7,value:"0",flex:1,spellcheck:!1,onchange:function(){var e,n,a=l.find("colorpicker")[0];return e=this.name(),n=this.value(),"hex"==e?(n="#"+n,i(n),void a.value(n)):(n={r:l.find("#r").value(),g:l.find("#g").value(),b:l.find("#b").value()},a.value(n),void i(n))}},items:[{name:"r",label:"R",autofocus:1},{name:"g",label:"G"},{name:"b",label:"B"},{name:"hex",label:"#",value:"000000"},{name:"preview",type:"container",border:1}]}]},onSubmit:function(){n("#"+this.toJSON().hex)}});i(a)}e.settings.color_picker_callback||(e.settings.color_picker_callback=n)}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/contextmenu/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("contextmenu",function(e){var t,n=e.settings.contextmenu_never_use_native;e.on("contextmenu",function(o){var i,c=e.getDoc();if(!o.ctrlKey||n){if(o.preventDefault(),tinymce.Env.mac&&tinymce.Env.webkit&&2==o.button&&c.caretRangeFromPoint&&e.selection.setRng(c.caretRangeFromPoint(o.x,o.y)),i=e.settings.contextmenu||"link image inserttable | cell row column deletetable",t)t.show();else{var a=[];tinymce.each(i.split(/[ ,]/),function(t){var n=e.menuItems[t];"|"==t&&(n={text:t}),n&&(n.shortcut="",a.push(n))});for(var r=0;r
",tinymce.each(a,function(a){var i=e+"/img/smiley-"+a+".gif";t+=' '}),t+=""}),t+=""}var i=[["cool","cry","embarassed","foot-in-mouth"],["frown","innocent","kiss","laughing"],["money-mouth","sealed","smile","surprised"],["tongue-out","undecided","wink","yell"]];t.addButton("emoticons",{type:"panelbutton",panel:{role:"application",autohide:!0,html:a,onclick:function(e){var a=t.dom.getParent(e.target,"a");a&&(t.insertContent(' '),this.hide())}},tooltip:"Emoticons"})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/example/dialog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
Custom dialog
5 | Input some text: 6 | 7 | 8 | -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/example/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("example",function(t,e){t.addButton("example",{text:"My button",icon:!1,onclick:function(){t.windowManager.open({title:"Example plugin",body:[{type:"textbox",name:"title",label:"Title"}],onsubmit:function(e){t.insertContent("Title: "+e.data.title)}})}}),t.addMenuItem("example",{text:"Example plugin",context:"tools",onclick:function(){t.windowManager.open({title:"TinyMCE site",url:e+"/dialog.html",width:600,height:400,buttons:[{text:"Insert",onclick:function(){var e=t.windowManager.getWindows()[0];t.insertContent(e.getContentWindow().document.getElementById("content").value),e.close()}},{text:"Close",onclick:"close"}]})}})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/example_dependency/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("example_dependency",function(){},["example"]); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/fullscreen/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("fullscreen",function(e){function t(){var e,t,n=window,i=document,l=i.body;return l.offsetWidth&&(e=l.offsetWidth,t=l.offsetHeight),n.innerWidth&&n.innerHeight&&(e=n.innerWidth,t=n.innerHeight),{w:e,h:t}}function n(){function n(){d.setStyle(a,"height",t().h-(h.clientHeight-a.clientHeight))}var u,h,a,f,m=document.body,g=document.documentElement;s=!s,h=e.getContainer(),u=h.style,a=e.getContentAreaContainer().firstChild,f=a.style,s?(i=f.width,l=f.height,f.width=f.height="100%",c=u.width,o=u.height,u.width=u.height="",d.addClass(m,"mce-fullscreen"),d.addClass(g,"mce-fullscreen"),d.addClass(h,"mce-fullscreen"),d.bind(window,"resize",n),n(),r=n):(f.width=i,f.height=l,c&&(u.width=c),o&&(u.height=o),d.removeClass(m,"mce-fullscreen"),d.removeClass(g,"mce-fullscreen"),d.removeClass(h,"mce-fullscreen"),d.unbind(window,"resize",r)),e.fire("FullscreenStateChanged",{state:s})}var i,l,r,c,o,s=!1,d=tinymce.DOM;return e.settings.inline?void 0:(e.on("init",function(){e.addShortcut("Ctrl+Alt+F","",n)}),e.on("remove",function(){r&&d.unbind(window,"resize",r)}),e.addCommand("mceFullScreen",n),e.addMenuItem("fullscreen",{text:"Fullscreen",shortcut:"Ctrl+Alt+F",selectable:!0,onClick:n,onPostRender:function(){var t=this;e.on("FullscreenStateChanged",function(e){t.active(e.state)})},context:"view"}),e.addButton("fullscreen",{tooltip:"Fullscreen",shortcut:"Ctrl+Alt+F",onClick:n,onPostRender:function(){var t=this;e.on("FullscreenStateChanged",function(e){t.active(e.state)})}}),{isFullscreen:function(){return s}})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/hr/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("hr",function(n){n.addCommand("InsertHorizontalRule",function(){n.execCommand("mceInsertContent",!1,"
")}),n.addButton("hr",{icon:"hr",tooltip:"Horizontal line",cmd:"InsertHorizontalRule"}),n.addMenuItem("hr",{icon:"hr",text:"Horizontal line",cmd:"InsertHorizontalRule",context:"insert"})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/image/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("image",function(e){function t(e,t){function i(e,i){n.parentNode&&n.parentNode.removeChild(n),t({width:e,height:i})}var n=document.createElement("img");n.onload=function(){i(n.clientWidth,n.clientHeight)},n.onerror=function(){i()};var a=n.style;a.visibility="hidden",a.position="fixed",a.bottom=a.left=0,a.width=a.height="auto",document.body.appendChild(n),n.src=e}function i(e,t,i){function n(e,i){return i=i||[],tinymce.each(e,function(e){var a={text:e.text||e.title};e.menu?a.menu=n(e.menu):(a.value=e.value,t(a)),i.push(a)}),i}return n(e,i||[])}function n(t){return function(){var i=e.settings.image_list;"string"==typeof i?tinymce.util.XHR.send({url:i,success:function(e){t(tinymce.util.JSON.parse(e))}}):"function"==typeof i?i(t):t(i)}}function a(n){function a(){var e,t,i,n;e=c.find("#width")[0],t=c.find("#height")[0],e&&t&&(i=e.value(),n=t.value(),c.find("#constrain")[0].checked()&&d&&u&&i&&n&&(d!=i?(n=Math.round(i/d*n),t.value(n)):(i=Math.round(n/u*i),e.value(i))),d=i,u=n)}function l(){function t(t){function i(){t.onload=t.onerror=null,e.selection&&(e.selection.select(t),e.nodeChanged())}t.onload=function(){m.width||m.height||!y||p.setAttribs(t,{width:t.clientWidth,height:t.clientHeight}),i()},t.onerror=i}s(),a(),m=tinymce.extend(m,c.toJSON()),m.alt||(m.alt=""),""===m.width&&(m.width=null),""===m.height&&(m.height=null),m.style||(m.style=null),m={src:m.src,alt:m.alt,width:m.width,height:m.height,style:m.style,"class":m["class"]},e.undoManager.transact(function(){return m.src?(f?p.setAttribs(f,m):(m.id="__mcenew",e.focus(),e.selection.setContent(p.createHTML("img",m)),f=p.get("__mcenew"),p.setAttrib(f,"id",null)),void t(f)):void(f&&(p.remove(f),e.focus(),e.nodeChanged()))})}function o(e){return e&&(e=e.replace(/px$/,"")),e}function r(i){var n=i.meta||{};g&&g.value(e.convertURL(this.value(),"src")),tinymce.each(n,function(e,t){c.find("#"+t).value(e)}),n.width||n.height||t(this.value(),function(e){e.width&&e.height&&y&&(d=e.width,u=e.height,c.find("#width").value(d),c.find("#height").value(u))})}function s(){function t(e){return e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e}if(e.settings.image_advtab){var i=c.toJSON(),n=p.parseStyle(i.style);delete n.margin,n["margin-top"]=n["margin-bottom"]=t(i.vspace),n["margin-left"]=n["margin-right"]=t(i.hspace),n["border-width"]=t(i.border),c.find("#style").value(p.serializeStyle(p.parseStyle(p.serializeStyle(n))))}}var c,d,u,g,h,m={},p=e.dom,f=e.selection.getNode(),y=e.settings.image_dimensions!==!1;d=p.getAttrib(f,"width"),u=p.getAttrib(f,"height"),"IMG"!=f.nodeName||f.getAttribute("data-mce-object")||f.getAttribute("data-mce-placeholder")?f=null:m={src:p.getAttrib(f,"src"),alt:p.getAttrib(f,"alt"),"class":p.getAttrib(f,"class"),width:d,height:u},n&&(g={type:"listbox",label:"Image list",values:i(n,function(t){t.value=e.convertURL(t.value||t.url,"src")},[{text:"None",value:""}]),value:m.src&&e.convertURL(m.src,"src"),onselect:function(e){var t=c.find("#alt");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),c.find("#src").value(e.control.value()).fire("change")},onPostRender:function(){g=this}}),e.settings.image_class_list&&(h={name:"class",type:"listbox",label:"Class",values:i(e.settings.image_class_list,function(t){t.value&&(t.textStyle=function(){return e.formatter.getCssText({inline:"img",classes:[t.value]})})})});var b=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:r},g];e.settings.image_description!==!1&&b.push({name:"alt",type:"textbox",label:"Image description"}),y&&b.push({type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:3,onchange:a,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:3,onchange:a,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}),b.push(h),e.settings.image_advtab?(f&&(m.hspace=o(f.style.marginLeft||f.style.marginRight),m.vspace=o(f.style.marginTop||f.style.marginBottom),m.border=o(f.style.borderWidth),m.style=e.dom.serializeStyle(e.dom.parseStyle(e.dom.getAttrib(f,"style")))),c=e.windowManager.open({title:"Insert/edit image",data:m,bodyType:"tabpanel",body:[{title:"General",type:"form",items:b},{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox"},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:s},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}],onSubmit:l})):c=e.windowManager.open({title:"Insert/edit image",data:m,body:b,onSubmit:l})}e.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:n(a),stateSelector:"img:not([data-mce-object],[data-mce-placeholder])"}),e.addMenuItem("image",{icon:"image",text:"Insert image",onclick:n(a),context:"insert",prependToContext:!0}),e.addCommand("mceImage",n(a))}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/importcss/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("importcss",function(t){function e(t){return"string"==typeof t?function(e){return-1!==e.indexOf(t)}:t instanceof RegExp?function(e){return t.test(e)}:t}function n(e,n){function i(t,e){var c,o=t.href;if(o&&n(o,e)){s(t.imports,function(t){i(t,!0)});try{c=t.cssRules||t.rules}catch(a){}s(c,function(t){t.styleSheet?i(t.styleSheet,!0):t.selectorText&&s(t.selectorText.split(","),function(t){r.push(tinymce.trim(t))})})}}var r=[],c={};s(t.contentCSS,function(t){c[t]=!0}),n||(n=function(t,e){return e||c[t]});try{s(e.styleSheets,function(t){i(t)})}catch(o){}return r}function i(e){var n,i=/^(?:([a-z0-9\-_]+))?(\.[a-z0-9_\-\.]+)$/i.exec(e);if(i){var r=i[1],s=i[2].substr(1).split(".").join(" "),c=tinymce.makeMap("a,img");return i[1]?(n={title:e},t.schema.getTextBlockElements()[r]?n.block=r:t.schema.getBlockElements()[r]||c[r.toLowerCase()]?n.selector=r:n.inline=r):i[2]&&(n={inline:"span",title:e.substr(1),classes:s}),t.settings.importcss_merge_classes!==!1?n.classes=s:n.attributes={"class":s},n}}var r=this,s=tinymce.each;t.on("renderFormatsMenu",function(c){var o=t.settings,a={},l=o.importcss_selector_converter||i,f=e(o.importcss_selector_filter),m=c.control;t.settings.importcss_append||m.items().remove();var u=[];tinymce.each(o.importcss_groups,function(t){t=tinymce.extend({},t),t.filter=e(t.filter),u.push(t)}),s(n(c.doc||t.getDoc(),e(o.importcss_file_filter)),function(e){if(-1===e.indexOf(".mce-")&&!a[e]&&(!f||f(e))){var n,i=l.call(r,e);if(i){var s=i.name||tinymce.DOM.uniqueId();if(u)for(var c=0;c'+n+"";var i=e.dom.getParent(e.selection.getStart(),"time");if(i)return void e.dom.setOuterHTML(i,n)}e.insertContent(n)}var n,r,i="Sun Mon Tue Wed Thu Fri Sat Sun".split(" "),d="Sunday Monday Tuesday Wednesday Thursday Friday Saturday Sunday".split(" "),c="Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split(" "),m="January February March April May June July August September October November December".split(" "),u=[];e.addCommand("mceInsertDate",function(){a(e.getParam("insertdatetime_dateformat",e.translate("%Y-%m-%d")))}),e.addCommand("mceInsertTime",function(){a(e.getParam("insertdatetime_timeformat",e.translate("%H:%M:%S")))}),e.addButton("insertdatetime",{type:"splitbutton",title:"Insert date/time",onclick:function(){a(n||r)},menu:u}),tinymce.each(e.settings.insertdatetime_formats||["%H:%M:%S","%Y-%m-%d","%I:%M:%S %p","%D"],function(e){r||(r=e),u.push({text:t(e),onclick:function(){n=e,a(e)}})}),e.addMenuItem("insertdatetime",{icon:"date",text:"Insert date/time",menu:u,context:"insert"})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/layer/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("layer",function(e){function t(e){do if(e.className&&-1!=e.className.indexOf("mceItemLayer"))return e;while(e=e.parentNode)}function o(t){var o=e.dom;tinymce.each(o.select("div,p",t),function(e){/^(absolute|relative|fixed)$/i.test(e.style.position)&&(e.hasVisual?o.addClass(e,"mceItemVisualAid"):o.removeClass(e,"mceItemVisualAid"),o.addClass(e,"mceItemLayer"))})}function d(o){var d,n,a=[],i=t(e.selection.getNode()),s=-1,l=-1;for(n=[],tinymce.walk(e.getBody(),function(e){1==e.nodeType&&/^(absolute|relative|static)$/i.test(e.style.position)&&n.push(e)},"childNodes"),d=0;d s&&n[d]==i&&(s=d);if(0>o){for(d=0;d -1?(n[s].style.zIndex=a[l],n[l].style.zIndex=a[s]):a[s]>0&&(n[s].style.zIndex=a[s]-1)}else{for(d=0;d a[s]){l=d;break}l>-1?(n[s].style.zIndex=a[l],n[l].style.zIndex=a[s]):n[s].style.zIndex=a[s]+1}e.execCommand("mceRepaint")}function n(){var t=e.dom,o=t.getPos(t.getParent(e.selection.getNode(),"*")),d=e.getBody();e.dom.add(d,"div",{style:{position:"absolute",left:o.x,top:o.y>20?o.y:20,width:100,height:100},"class":"mceItemVisualAid mceItemLayer"},e.selection.getContent()||e.getLang("layer.content")),tinymce.Env.ie&&t.setHTML(d,d.innerHTML)}function a(){var o=t(e.selection.getNode());o||(o=e.dom.getParent(e.selection.getNode(),"DIV,P,IMG")),o&&("absolute"==o.style.position.toLowerCase()?(e.dom.setStyles(o,{position:"",left:"",top:"",width:"",height:""}),e.dom.removeClass(o,"mceItemVisualAid"),e.dom.removeClass(o,"mceItemLayer")):(o.style.left||(o.style.left="20px"),o.style.top||(o.style.top="20px"),o.style.width||(o.style.width=o.width?o.width+"px":"100px"),o.style.height||(o.style.height=o.height?o.height+"px":"100px"),o.style.position="absolute",e.dom.setAttrib(o,"data-mce-style",""),e.addVisual(e.getBody())),e.execCommand("mceRepaint"),e.nodeChanged())}e.addCommand("mceInsertLayer",n),e.addCommand("mceMoveForward",function(){d(1)}),e.addCommand("mceMoveBackward",function(){d(-1)}),e.addCommand("mceMakeAbsolute",function(){a()}),e.addButton("moveforward",{title:"layer.forward_desc",cmd:"mceMoveForward"}),e.addButton("movebackward",{title:"layer.backward_desc",cmd:"mceMoveBackward"}),e.addButton("absolute",{title:"layer.absolute_desc",cmd:"mceMakeAbsolute"}),e.addButton("insertlayer",{title:"layer.insertlayer_desc",cmd:"mceInsertLayer"}),e.on("init",function(){tinymce.Env.ie&&e.getDoc().execCommand("2D-Position",!1,!0)}),e.on("mouseup",function(o){var d=t(o.target);d&&e.dom.setAttrib(d,"data-mce-style","")}),e.on("mousedown",function(o){var d,n=o.target,a=e.getDoc();tinymce.Env.gecko&&(t(n)?"on"!==a.designMode&&(a.designMode="on",n=a.body,d=n.parentNode,d.removeChild(n),d.appendChild(n)):"on"==a.designMode&&(a.designMode="off"))}),e.on("NodeChange",o)}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/legacyoutput/plugin.min.js: -------------------------------------------------------------------------------- 1 | !function(e){e.on("AddEditor",function(e){e.editor.settings.inline_styles=!1}),e.PluginManager.add("legacyoutput",function(t,n,i){t.on("init",function(){var n="p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li,table,img",i=e.explode(t.settings.font_size_style_values),a=t.schema;t.formatter.register({alignleft:{selector:n,attributes:{align:"left"}},aligncenter:{selector:n,attributes:{align:"center"}},alignright:{selector:n,attributes:{align:"right"}},alignjustify:{selector:n,attributes:{align:"justify"}},bold:[{inline:"b",remove:"all"},{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}}],italic:[{inline:"i",remove:"all"},{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}}],underline:[{inline:"u",remove:"all"},{inline:"span",styles:{textDecoration:"underline"},exact:!0}],strikethrough:[{inline:"strike",remove:"all"},{inline:"span",styles:{textDecoration:"line-through"},exact:!0}],fontname:{inline:"font",attributes:{face:"%value"}},fontsize:{inline:"font",attributes:{size:function(t){return e.inArray(i,t.value)+1}}},forecolor:{inline:"font",attributes:{color:"%value"}},hilitecolor:{inline:"font",styles:{backgroundColor:"%value"}}}),e.each("b,i,u,strike".split(","),function(e){a.addValidElements(e+"[*]")}),a.getElementRule("font")||a.addValidElements("font[face|size|color|style]"),e.each(n.split(","),function(e){var t=a.getElementRule(e);t&&(t.attributes.align||(t.attributes.align={},t.attributesOrder.push("align")))})}),t.addButton("fontsizeselect",function(){var e=[],n="8pt=1 10pt=2 12pt=3 14pt=4 18pt=5 24pt=6 36pt=7",i=t.settings.fontsize_formats||n;return t.$.each(i.split(" "),function(t,n){var i=n,a=n,o=n.split("=");o.length>1&&(i=o[0],a=o[1]),e.push({text:i,value:a})}),{type:"listbox",text:"Font Sizes",tooltip:"Font Sizes",values:e,fixedWidth:!0,onPostRender:function(){var e=this;t.on("NodeChange",function(){var n;n=t.dom.getParent(t.selection.getNode(),"font"),e.value(n?n.size:"")})},onclick:function(e){e.control.settings.value&&t.execCommand("FontSize",!1,e.control.settings.value)}}}),t.addButton("fontselect",function(){function e(e){e=e.replace(/;$/,"").split(";");for(var t=e.length;t--;)e[t]=e[t].split("=");return e}var n="Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats",a=[],o=e(t.settings.font_formats||n);return i.each(o,function(e,t){a.push({text:{raw:t[0]},value:t[1],textStyle:-1==t[1].indexOf("dings")?"font-family:"+t[1]:""})}),{type:"listbox",text:"Font Family",tooltip:"Font Family",values:a,fixedWidth:!0,onPostRender:function(){var e=this;t.on("NodeChange",function(){var n;n=t.dom.getParent(t.selection.getNode(),"font"),e.value(n?n.face:"")})},onselect:function(e){e.control.settings.value&&t.execCommand("FontName",!1,e.control.settings.value)}}})})}(tinymce); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/link/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("link",function(t){function e(e){return function(){var n=t.settings.link_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(t){e(tinymce.util.JSON.parse(t))}}):"function"==typeof n?n(e):e(n)}}function n(t,e,n){function i(t,n){return n=n||[],tinymce.each(t,function(t){var l={text:t.text||t.title};t.menu?l.menu=i(t.menu):(l.value=t.value,e&&e(l)),n.push(l)}),n}return i(t,n||[])}function i(e){function i(t){var e=f.find("#text");(!e.value()||t.lastControl&&e.value()==t.lastControl.text())&&e.value(t.control.text()),f.find("#href").value(t.control.value())}function l(e){var n=[];return tinymce.each(t.dom.select("a:not([href])"),function(t){var i=t.name||t.id;i&&n.push({text:i,value:"#"+i,selected:-1!=e.indexOf("#"+i)})}),n.length?(n.unshift({text:"None",value:""}),{name:"anchor",type:"listbox",label:"Anchors",values:n,onselect:i}):void 0}function a(){!c&&0===y.text.length&&d&&this.parent().parent().find("#text")[0].value(this.value())}function o(e){var n=e.meta||{};x&&x.value(t.convertURL(this.value(),"href")),tinymce.each(e.meta,function(t,e){f.find("#"+e).value(t)}),n.text||a.call(this)}function r(t){var e=b.getContent();if(/]+>[^<]+<\/a>$/.test(e)||-1==e.indexOf("href=")))return!1;if(t){var n,i=t.childNodes;if(0===i.length)return!1;for(n=i.length-1;n>=0;n--)if(3!=i[n].nodeType)return!1}return!0}var s,u,c,f,d,g,x,v,h,m,p,k,y={},b=t.selection,_=t.dom;s=b.getNode(),u=_.getParent(s,"a[href]"),d=r(),y.text=c=u?u.innerText||u.textContent:b.getContent({format:"text"}),y.href=u?_.getAttrib(u,"href"):"",(k=_.getAttrib(u,"target"))?y.target=k:t.settings.default_link_target&&(y.target=t.settings.default_link_target),(k=_.getAttrib(u,"rel"))&&(y.rel=k),(k=_.getAttrib(u,"class"))&&(y["class"]=k),(k=_.getAttrib(u,"title"))&&(y.title=k),d&&(g={name:"text",type:"textbox",size:40,label:"Text to display",onchange:function(){y.text=this.value()}}),e&&(x={type:"listbox",label:"Link list",values:n(e,function(e){e.value=t.convertURL(e.value||e.url,"href")},[{text:"None",value:""}]),onselect:i,value:t.convertURL(y.href,"href"),onPostRender:function(){x=this}}),t.settings.target_list!==!1&&(t.settings.target_list||(t.settings.target_list=[{text:"None",value:""},{text:"New window",value:"_blank"}]),h={name:"target",type:"listbox",label:"Target",values:n(t.settings.target_list)}),t.settings.rel_list&&(v={name:"rel",type:"listbox",label:"Rel",values:n(t.settings.rel_list)}),t.settings.link_class_list&&(m={name:"class",type:"listbox",label:"Class",values:n(t.settings.link_class_list,function(e){e.value&&(e.textStyle=function(){return t.formatter.getCssText({inline:"a",classes:[e.value]})})})}),t.settings.link_title!==!1&&(p={name:"title",type:"textbox",label:"Title",value:y.title}),f=t.windowManager.open({title:"Insert link",data:y,body:[{name:"href",type:"filepicker",filetype:"file",size:40,autofocus:!0,label:"Url",onchange:o,onkeyup:a},g,p,l(y.href),x,v,h,m],onSubmit:function(e){function n(e,n){var i=t.selection.getRng();window.setTimeout(function(){t.windowManager.confirm(e,function(e){t.selection.setRng(i),n(e)})},0)}function i(){var e={href:l,target:y.target?y.target:null,rel:y.rel?y.rel:null,"class":y["class"]?y["class"]:null,title:y.title?y.title:null};u?(t.focus(),d&&y.text!=c&&("innerText"in u?u.innerText=y.text:u.textContent=y.text),_.setAttribs(u,e),b.select(u),t.undoManager.add()):d?t.insertContent(_.createHTML("a",e,_.encode(y.text))):t.execCommand("mceInsertLink",!1,e)}var l;return y=tinymce.extend(y,e.data),(l=y.href)?l.indexOf("@")>0&&-1==l.indexOf("//")&&-1==l.indexOf("mailto:")?void n("The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?",function(t){t&&(l="mailto:"+l),i()}):/^\s*www\./i.test(l)?void n("The URL you entered seems to be an external link. Do you want to add the required http:// prefix?",function(t){t&&(l="http://"+l),i()}):void i():void t.execCommand("unlink")}})}t.addButton("link",{icon:"link",tooltip:"Insert/edit link",shortcut:"Ctrl+K",onclick:e(i),stateSelector:"a[href]"}),t.addButton("unlink",{icon:"unlink",tooltip:"Remove link",cmd:"unlink",stateSelector:"a[href]"}),t.addShortcut("Ctrl+K","",e(i)),t.addCommand("mceLink",e(i)),this.showDialog=i,t.addMenuItem("link",{icon:"link",text:"Insert link",shortcut:"Ctrl+K",onclick:e(i),stateSelector:"a[href]",context:"insert",prependToContext:!0})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/media/moxieplayer.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/batimentb/shelf-cms/e3da039735160916a72c232afb125b98625eae21/shelf/plugins/wysiwyg/static/tinymce/plugins/media/moxieplayer.swf -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/nonbreaking/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("nonbreaking",function(n){var e=n.getParam("nonbreaking_force_tab");if(n.addCommand("mceNonBreaking",function(){n.insertContent(n.plugins.visualchars&&n.plugins.visualchars.state?' ':" "),n.dom.setAttrib(n.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),n.addButton("nonbreaking",{title:"Insert nonbreaking space",cmd:"mceNonBreaking"}),n.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),e){var a=+e>1?+e:3;n.on("keydown",function(e){if(9==e.keyCode){if(e.shiftKey)return;e.preventDefault();for(var t=0;a>t;t++)n.execCommand("mceNonBreaking")}})}}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/noneditable/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("noneditable",function(e){function t(e){var t;if(1===e.nodeType){if(t=e.getAttribute(u),t&&"inherit"!==t)return t;if(t=e.contentEditable,"inherit"!==t)return t}return null}function n(e){for(var n;e;){if(n=t(e))return"false"===n?e:null;e=e.parentNode}}function r(){function r(e){for(;e;){if(e.id===g)return e;e=e.parentNode}}function a(e){var t;if(e)for(t=new f(e,e),e=t.current();e;e=t.next())if(3===e.nodeType)return e}function i(n,r){var a,i;return"false"===t(n)&&u.isBlock(n)?void s.select(n):(i=u.createRng(),"true"===t(n)&&(n.firstChild||n.appendChild(e.getDoc().createTextNode(" ")),n=n.firstChild,r=!0),a=u.create("span",{id:g,"data-mce-bogus":!0},m),r?n.parentNode.insertBefore(a,n):u.insertAfter(a,n),i.setStart(a.firstChild,1),i.collapse(!0),s.setRng(i),a)}function o(e){var t,n,i,o;if(e)t=s.getRng(!0),t.setStartBefore(e),t.setEndBefore(e),n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0),s.setRng(t);else for(i=r(s.getStart());(e=u.get(g))&&e!==o;)i!==e&&(n=a(e),n&&n.nodeValue.charAt(0)==m&&(n=n.deleteData(0,1)),u.remove(e,!0)),o=e}function l(){function e(e,n){var r,a,i,o,l;if(r=d.startContainer,a=d.startOffset,3==r.nodeType){if(l=r.nodeValue.length,a>0&&l>a||(n?a==l:0===a))return}else{if(!(a 0?a-1:a;r=r.childNodes[u],r.hasChildNodes()&&(r=r.firstChild)}for(i=new f(r,e);o=i[n?"prev":"next"]();){if(3===o.nodeType&&o.nodeValue.length>0)return;if("true"===t(o))return o}return e}var r,a,l,d,u;o(),l=s.isCollapsed(),r=n(s.getStart()),a=n(s.getEnd()),(r||a)&&(d=s.getRng(!0),l?(r=r||a,(u=e(r,!0))?i(u,!0):(u=e(r,!1))?i(u,!1):s.select(r)):(d=s.getRng(!0),r&&d.setStartBefore(r),a&&d.setEndAfter(a),s.setRng(d)))}function d(a){function i(e,t){for(;e=e[t?"previousSibling":"nextSibling"];)if(3!==e.nodeType||e.nodeValue.length>0)return e}function d(e,t){s.select(e),s.collapse(t)}function g(a){function i(e){for(var t=d;t;){if(t===e)return;t=t.parentNode}u.remove(e),l()}function o(){var r,o,l=e.schema.getNonEmptyElements();for(o=new tinymce.dom.TreeWalker(d,e.getBody());(r=a?o.prev():o.next())&&!l[r.nodeName.toLowerCase()]&&!(3===r.nodeType&&tinymce.trim(r.nodeValue).length>0);)if("false"===t(r))return i(r),!0;return n(r)?!0:!1}var f,d,c,g;if(s.isCollapsed()){if(f=s.getRng(!0),d=f.startContainer,c=f.startOffset,d=r(d)||d,g=n(d))return i(g),!1;if(3==d.nodeType&&(a?c>0:c h||h>124)&&h!=c.DELETE&&h!=c.BACKSPACE){if((tinymce.isMac?a.metaKey:a.ctrlKey)&&(67==h||88==h||86==h))return;if(a.preventDefault(),h==c.LEFT||h==c.RIGHT){var y=h==c.LEFT;if(e.dom.isBlock(m)){var T=y?m.previousSibling:m.nextSibling,C=new f(T,T),b=y?C.prev():C.next();d(b,!y)}else d(m,y)}}else if(h==c.LEFT||h==c.RIGHT||h==c.BACKSPACE||h==c.DELETE){if(p=r(v)){if(h==c.LEFT||h==c.BACKSPACE)if(m=i(p,!0),m&&"false"===t(m)){if(a.preventDefault(),h!=c.LEFT)return void u.remove(m);d(m,!0)}else o(p);if(h==c.RIGHT||h==c.DELETE)if(m=i(p),m&&"false"===t(m)){if(a.preventDefault(),h!=c.RIGHT)return void u.remove(m);d(m,!1)}else o(p)}if((h==c.BACKSPACE||h==c.DELETE)&&!g(h==c.BACKSPACE))return a.preventDefault(),!1}}var u=e.dom,s=e.selection,g="mce_noneditablecaret",m="";e.on("mousedown",function(n){var r=e.selection.getNode();"false"===t(r)&&r==n.target&&l()}),e.on("mouseup keyup",l),e.on("keydown",d)}function a(t){var n=l.length,r=t.content,a=tinymce.trim(o);if("raw"!=t.format){for(;n--;)r=r.replace(l[n],function(t){var n=arguments,i=n[n.length-2];return i>0&&'"'==r.charAt(i-1)?t:''+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+""});t.content=r}}var i,o,l,f=tinymce.dom.TreeWalker,d="contenteditable",u="data-mce-"+d,c=tinymce.util.VK;i=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",o=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ",l=e.getParam("noneditable_regexp"),l&&!l.length&&(l=[l]),e.on("PreInit",function(){r(),l&&e.on("BeforeSetContent",a),e.parser.addAttributeFilter("class",function(e){for(var t,n,r=e.length;r--;)n=e[r],t=" "+n.attr("class")+" ",-1!==t.indexOf(i)?n.attr(u,"true"):-1!==t.indexOf(o)&&n.attr(u,"false")}),e.serializer.addAttributeFilter(u,function(e){for(var t,n=e.length;n--;)t=e[n],l&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):(t.attr(d,null),t.attr(u,null))}),e.parser.addAttributeFilter(d,function(e){for(var t,n=e.length;n--;)t=e[n],t.attr(u,t.attr(d)),t.attr(d,null)})}),e.on("drop",function(e){n(e.target)&&e.preventDefault()})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/pagebreak/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("pagebreak",function(e){var a="mce-pagebreak",t=e.getParam("pagebreak_separator",""),n=new RegExp(t.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),r=' ';e.addCommand("mcePageBreak",function(){e.insertContent(e.settings.pagebreak_split_block?"
"+r+"
":r)}),e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),e.on("ResolveName",function(t){"IMG"==t.target.nodeName&&e.dom.hasClass(t.target,a)&&(t.name="pagebreak")}),e.on("click",function(t){t=t.target,"IMG"===t.nodeName&&e.dom.hasClass(t,a)&&e.selection.select(t)}),e.on("BeforeSetContent",function(e){e.content=e.content.replace(n,r)}),e.on("PreInit",function(){e.serializer.addNodeFilter("img",function(a){for(var n,r,c=a.length;c--;)if(n=a[c],r=n.attr("class"),r&&-1!==r.indexOf("mce-pagebreak")){var o=n.parent;if(e.schema.getBlockElements()[o.name]&&e.settings.pagebreak_split_block){o.type=3,o.value=t,o.raw=!0,n.remove();continue}n.type=3,n.value=t,n.raw=!0}})})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/preview/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("preview",function(e){var t=e.settings,i=!tinymce.Env.ie;e.addCommand("mcePreview",function(){e.windowManager.open({title:"Preview",width:parseInt(e.getParam("plugin_preview_width","650"),10),height:parseInt(e.getParam("plugin_preview_height","500"),10),html:'",buttons:{text:"Close",onclick:function(){this.parent().parent().close()}},onPostRender:function(){var n,a="";a+='',tinymce.each(e.contentCSS,function(t){a+=''});var r=t.body_id||"tinymce";-1!=r.indexOf("=")&&(r=e.getParam("body_id","","hash"),r=r[e.id]||r);var d=t.body_class||"";-1!=d.indexOf("=")&&(d=e.getParam("body_class","","hash"),d=d[e.id]||"");var o=e.settings.directionality?' dir="'+e.settings.directionality+'"':"";if(n=""+a+'"+e.getContent()+"",i)this.getEl("body").firstChild.src="data:text/html;charset=utf-8,"+encodeURIComponent(n);else{var s=this.getEl("body").firstChild.contentWindow.document;s.open(),s.write(n),s.close()}}})}),e.addButton("preview",{title:"Preview",cmd:"mcePreview"}),e.addMenuItem("preview",{text:"Preview",cmd:"mcePreview",context:"view"})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/print/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("print",function(t){t.addCommand("mcePrint",function(){t.getWin().print()}),t.addButton("print",{title:"Print",cmd:"mcePrint"}),t.addShortcut("Ctrl+P","","mcePrint"),t.addMenuItem("print",{text:"Print",cmd:"mcePrint",icon:"print",shortcut:"Ctrl+P",context:"file"})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/save/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("save",function(e){function a(){var a;return a=tinymce.DOM.getParent(e.id,"form"),!e.getParam("save_enablewhendirty",!0)||e.isDirty()?(tinymce.triggerSave(),e.getParam("save_onsavecallback")?void(e.execCallback("save_onsavecallback",e)&&(e.startContent=tinymce.trim(e.getContent({format:"raw"})),e.nodeChanged())):void(a?(e.isNotDirty=!0,(!a.onsubmit||a.onsubmit())&&("function"==typeof a.submit?a.submit():e.windowManager.alert("Error: Form submit field collision.")),e.nodeChanged()):e.windowManager.alert("Error: No form element found."))):void 0}function n(){var a=tinymce.trim(e.startContent);return e.getParam("save_oncancelcallback")?void e.execCallback("save_oncancelcallback",e):(e.setContent(a),e.undoManager.clear(),void e.nodeChanged())}function t(){var a=this;e.on("nodeChange",function(){a.disabled(e.getParam("save_enablewhendirty",!0)&&!e.isDirty())})}e.addCommand("mceSave",a),e.addCommand("mceCancel",n),e.addButton("save",{icon:"save",text:"Save",cmd:"mceSave",disabled:!0,onPostRender:t}),e.addButton("cancel",{text:"Cancel",icon:!1,cmd:"mceCancel",disabled:!0,onPostRender:t}),e.addShortcut("ctrl+s","","mceSave")}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/tabfocus/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("tabfocus",function(e){function n(e){9!==e.keyCode||e.ctrlKey||e.altKey||e.metaKey||e.preventDefault()}function t(n){function t(n){function t(e){return"BODY"===e.nodeName||"hidden"!=e.type&&"none"!=e.style.display&&"hidden"!=e.style.visibility&&t(e.parentNode)}function r(e){return e.tabIndex||"INPUT"==e.nodeName||"TEXTAREA"==e.nodeName}function c(e){return!r(e)&&"-1"!=e.getAttribute("tabindex")&&t(e)}if(u=i.select(":input:enabled,*[tabindex]:not(iframe)"),o(u,function(n,t){return n.id==e.id?(a=t,!1):void 0}),n>0){for(d=a+1;d =0;d--)if(c(u[d]))return u[d];return null}var a,u,c,d;if(!(9!==n.keyCode||n.ctrlKey||n.altKey||n.metaKey)&&(c=r(e.getParam("tab_focus",e.getParam("tabfocus_elements",":prev,:next"))),1==c.length&&(c[1]=c[0],c[0]=":prev"),u=n.shiftKey?":prev"==c[0]?t(-1):i.get(c[0]):":next"==c[1]?t(1):i.get(c[1]))){var y=tinymce.get(u.id||u.name);u.id&&y?y.focus():window.setTimeout(function(){tinymce.Env.webkit||window.focus(),u.focus()},10),n.preventDefault()}}var i=tinymce.DOM,o=tinymce.each,r=tinymce.explode;e.on("init",function(){e.inline&&tinymce.DOM.setAttrib(e.getBody(),"tabIndex",null)}),e.on("keyup",n),tinymce.Env.gecko?e.on("keypress keydown",t):e.on("keydown",t)}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/template/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("template",function(e){function t(t){return function(){var a=e.settings.templates;"string"==typeof a?tinymce.util.XHR.send({url:a,success:function(e){t(tinymce.util.JSON.parse(e))}}):t(a)}}function a(t){function a(t){function a(t){if(-1==t.indexOf("")){var a="";tinymce.each(e.contentCSS,function(t){a+=''}),t=""+a+""+t+""}t=r(t,"template_preview_replace_values");var l=n.find("iframe")[0].getEl().contentWindow.document;l.open(),l.write(t),l.close()}var c=t.control.value();c.url?tinymce.util.XHR.send({url:c.url,success:function(e){l=e,a(l)}}):(l=c.content,a(l)),n.find("#description")[0].text(t.control.value().description)}var n,l,i=[];return t&&0!==t.length?(tinymce.each(t,function(e){i.push({selected:!i.length,text:e.title,value:{url:e.url,content:e.content,description:e.description}})}),n=e.windowManager.open({title:"Insert template",layout:"flex",direction:"column",align:"stretch",padding:15,spacing:10,items:[{type:"form",flex:0,padding:0,items:[{type:"container",label:"Templates",items:{type:"listbox",label:"Templates",name:"template",values:i,onselect:a}}]},{type:"label",name:"description",label:"Description",text:" "},{type:"iframe",flex:1,border:1}],onsubmit:function(){c(!1,l)},width:e.getParam("template_popup_width",600),height:e.getParam("template_popup_height",500)}),void n.find("listbox")[0].fire("select")):void e.windowManager.alert("No templates defined")}function n(t,a){function n(e,t){if(e=""+e,e.length 0&&(o=p.create("div",null),o.appendChild(s[0].cloneNode(!0))),i(p.select("*",o),function(t){c(t,e.getParam("template_cdate_classes","cdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_cdate_format",e.getLang("template.cdate_format")))),c(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format")))),c(t,e.getParam("template_selected_content_classes","selcontent").replace(/\s+/g,"|"))&&(t.innerHTML=m)}),l(o),e.execCommand("mceInsertContent",!1,o.innerHTML),e.addVisual()}var i=tinymce.each;e.addCommand("mceInsertTemplate",c),e.addButton("template",{title:"Insert template",onclick:t(a)}),e.addMenuItem("template",{text:"Insert template",onclick:t(a),context:"insert"}),e.on("PreProcess",function(t){var a=e.dom;i(a.select("div",t.node),function(t){a.hasClass(t,"mceTmpl")&&(i(a.select("*",t),function(t){a.hasClass(t,e.getParam("template_mdate_classes","mdate").replace(/\s+/g,"|"))&&(t.innerHTML=n(e.getParam("template_mdate_format",e.getLang("template.mdate_format"))))}),l(t))})})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/textcolor/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("textcolor",function(t){function e(e){var o;return t.dom.getParents(t.selection.getStart(),function(t){var r;(r=t.style["forecolor"==e?"color":"background-color"])&&(o=r)}),o}function o(){var e,o,r=[];for(o=t.settings.textcolor_map||["000000","Black","993300","Burnt orange","333300","Dark olive","003300","Dark green","003366","Dark azure","000080","Navy Blue","333399","Indigo","333333","Very dark gray","800000","Maroon","FF6600","Orange","808000","Olive","008000","Green","008080","Teal","0000FF","Blue","666699","Grayish blue","808080","Gray","FF0000","Red","FF9900","Amber","99CC00","Yellow green","339966","Sea green","33CCCC","Turquoise","3366FF","Royal blue","800080","Purple","999999","Medium gray","FF00FF","Magenta","FFCC00","Gold","FFFF00","Yellow","00FF00","Lime","00FFFF","Aqua","00CCFF","Sky blue","993366","Red violet","FFFFFF","White","FF99CC","Pink","FFCC99","Peach","FFFF99","Light yellow","CCFFCC","Pale green","CCFFFF","Pale cyan","99CCFF","Light sky blue","CC99FF","Plum"],e=0;e '+(o?"×":"")+""}var r,l,a,n,c,d,u,g=this,m=g._id,F=0;for(r=o(),r.push({text:tinymce.translate("No color"),color:"transparent"}),a='',n=r.length-1,d=0;s>d;d++){for(a+="
"}function l(e,o){t.focus(),t.formatter.apply(e,{value:o}),t.nodeChanged()}function a(e){t.focus(),t.formatter.remove(e,{value:null},null,!0),t.nodeChanged()}function n(o){function r(t){s.hidePanel(),s.color(t),l(s.settings.format,t)}function n(t,e){t.style.background=e,t.setAttribute("data-mce-color",e)}var c,s=this.parent();if(tinymce.DOM.getParent(o.target,".mce-custom-color-btn")&&(s.hidePanel(),t.settings.color_picker_callback.call(t,function(t){var e,o,l,a=s.panel.getEl().getElementsByTagName("table")[0];for(e=tinymce.map(a.rows[a.rows.length-1].childNodes,function(t){return t.firstChild}),l=0;l",c=0;i>c;c++)u=d*i+c,u>n?a+=" "}if(t.settings.color_picker_callback){for(a+='":(l=r[u],a+=e(l.color,l.text));a+=" ",a+=" ",c=0;i>c;c++)a+=e("","Custom color");a+=" "}return a+="l;l++)n(e[l],e[l+1].getAttribute("data-mce-color"));n(o,t),r(t)},e(s.settings.format))),c=o.target.getAttribute("data-mce-color")){if(this.lastId&&document.getElementById(this.lastId).setAttribute("aria-selected",!1),o.target.setAttribute("aria-selected",!0),this.lastId=o.target.id,"transparent"==c)return a(s.settings.format),void s.hidePanel();r(c)}else null!==c&&s.hidePanel()}function c(){var t=this;t._color&&l(t.settings.format,t._color)}var i,s;s=t.settings.textcolor_rows||5,i=t.settings.textcolor_cols||8,t.addButton("forecolor",{type:"colorbutton",tooltip:"Text color",format:"forecolor",panel:{role:"application",ariaRemember:!0,html:r,onclick:n},onclick:c}),t.addButton("backcolor",{type:"colorbutton",tooltip:"Background color",format:"hilitecolor",panel:{role:"application",ariaRemember:!0,html:r,onclick:n},onclick:c})}); -------------------------------------------------------------------------------- /shelf/plugins/wysiwyg/static/tinymce/plugins/textpattern/plugin.min.js: -------------------------------------------------------------------------------- 1 | tinymce.PluginManager.add("textpattern",function(t){function e(){return l&&(i.sort(function(t,e){return t.start.length>e.start.length?-1:t.start.length $1
35 | I forgot my password 36 |
37 | {% endif %} 38 | {% if security.confirmable %} 39 |40 | Send confirmation 41 |
42 | {% endif %} 43 | {% if security.registerable %} 44 |45 | Create an account 46 |
47 | {% endif %} 48 |49 | Back to login 50 |
51 | {% endmacro %} -------------------------------------------------------------------------------- /shelf/templates/shelf-security/base.html: -------------------------------------------------------------------------------- 1 | {% import 'layout.html' as layout with context -%} 2 | {% import 'shelf/static.html' as shelf_static with context %} 3 | {% import 'admin/static.html' as admin_static with context %} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |51 | 0 sur {{ data|length }} sélectionnés 52 | {% if num_pages > 1 %} 53 | 54 | {% endif %} 55 |
56 | {% if num_pages > 1 %} 57 | 61 | {% endif %} 62 | {% endif %} 63 | {% endmacro %} 64 | 65 | {% macro script(message, actions, actions_confirmation) %} 66 | {% if actions %} 67 | 68 | 71 | {% endif %} 72 | {% endmacro %} 73 | -------------------------------------------------------------------------------- /shelf/templates/shelf/base.html: -------------------------------------------------------------------------------- 1 | {% extends 'admin/base.html' %} 2 | {% import 'shelf/static.html' as shelf_static with context %} 3 | {% import 'shelf/lib.html' as lib with context %} 4 | 5 | {% block head_css %} 6 | 7 | 8 | 9 | 10 | {{ lib.get_view_extensions("head_css") }} 11 | {% endblock %} 12 | 13 | {% block page_body %} 14 |