├── .gitignore ├── .travis.yml ├── CHANGES.md ├── Gruntfile.coffee ├── LICENSE ├── README.md ├── bower.json ├── design ├── create.png └── create.svg ├── dist └── create.js ├── examples ├── demo.css ├── example-aloha.html ├── example-ckeditor.html ├── example-geo.html ├── example-medium.html ├── example-redactor.html ├── example-tinymce.html ├── example-withtype.html ├── example.html └── font-awesome │ ├── css │ ├── font-awesome-ie7.css │ └── font-awesome.css │ └── fonts │ ├── FontAwesome.otf │ ├── fontawesome-webfont.eot │ ├── fontawesome-webfont.svg │ ├── fontawesome-webfont.svgz │ ├── fontawesome-webfont.ttf │ └── fontawesome-webfont.woff ├── locale ├── locale_bg.js ├── locale_cs.js ├── locale_da.js ├── locale_de.js ├── locale_en.js ├── locale_es.js ├── locale_fi.js ├── locale_fr.js ├── locale_he.js ├── locale_it.js ├── locale_lt.js ├── locale_nl.js ├── locale_no.js ├── locale_pl.js ├── locale_pt_BR.js ├── locale_ro.js ├── locale_ru.js └── locale_sv.js ├── manifest.yml ├── nodejs └── static.js ├── package.json ├── src ├── collectionWidgets │ ├── jquery.Midgard.midgardCreateCollectionAdd.js │ └── jquery.Midgard.midgardCreateCollectionAddBetween.js ├── editingWidgets │ ├── jquery.Midgard.midgardEditableBase.js │ ├── jquery.Midgard.midgardEditableEditorAloha.js │ ├── jquery.Midgard.midgardEditableEditorCKEditor.js │ ├── jquery.Midgard.midgardEditableEditorHallo.js │ ├── jquery.Midgard.midgardEditableEditorMedium.js │ ├── jquery.Midgard.midgardEditableEditorRedactor.js │ └── jquery.Midgard.midgardEditableEditorTinyMCE.js ├── jquery.Midgard.midgardCreate.js ├── jquery.Midgard.midgardEditable.js ├── jquery.Midgard.midgardMetadata.js ├── jquery.Midgard.midgardNotifications.js ├── jquery.Midgard.midgardStorage.js ├── jquery.Midgard.midgardToolbar.js ├── jquery.Midgard.midgardWorkflows.js ├── metadataWidgets │ ├── jquery.Midgard.midgardGeo.js │ └── jquery.Midgard.midgardTags.js └── midgardCreate.localize.js ├── test ├── index.html ├── midgardCreate.js ├── midgardEditable.js └── qunit │ ├── qunit.css │ ├── qunit.js │ └── run.js └── themes ├── create-ui ├── css │ └── create-ui.css └── img │ ├── create-ui-bg.png │ ├── create-ui-logo.png │ └── create-ui-xdivider.png ├── insertimage.css ├── midgard-geo ├── pin-regular.png ├── pin-selected.png ├── pin-unrelevant-grey.png └── pin-unrelevant.png ├── midgard-notifications ├── leftright.png ├── midgardnotif.css └── topbottom.png └── midgard-tags ├── close_button.png ├── cornerclose.png ├── cornersettings_large.png ├── cornersettings_large_hand.png ├── cornersettings_small.png ├── settingsh2icon.png └── tags.css /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | merged/ 4 | npm-debug.log 5 | .DS_Store 6 | .idea 7 | dist/create-editonly* 8 | dist/*.min.js 9 | examples/redactor.* 10 | components/ 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '4.6' 4 | before_script: 5 | - npm install -g grunt-cli 6 | script: grunt crossbrowser 7 | env: 8 | global: 9 | - secure: HmsTWiwibB28awz5YIa3WmvhrDroWypjW7Hivn57Mz3tKW8J2/o30ZS06FmBROEEeaHGbVTyb0/DSfWS/mDGM8SweDXIV+xqwDLLUa/PdTgX4ROjUVofNHaHxzpUECnJJm8GV/euB8FgZNo9Wu1JBUCA/6HoLnCmlqK4cNSD5VY= 10 | - secure: e43D09e2fXuDcjw+P+1mtvpAnxb4730Wbtwd3Xb+xueoBQFP/cBdKx8Qy6f+kV9SXy7eVEzDC3MbxJtdtuYGlTY7oV3f3rmA00UhHokGbgw2SnEtCgzN7Eedtskz6ybbgy0FyMoF4CMg7R5mW+sxe40DbEyS2VdD19vOdXCNF9k= 11 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | Create.js ChangeLog 2 | =================== 3 | 4 | ## 1.0.0beta1 (January 22nd 2015) 5 | 6 | * The basic `editWidget` now ignores all formatting 7 | * CKEditor 4 is now configurable using Create's `editorOptions` 8 | * Initial support for the [Medium Editor](http://daviferreira.github.io/medium-editor/) 9 | * Support for Font Awesome 4.x 10 | * Dependencies are now installed via Bower 11 | 12 | ## 1.0.0alpha4 (September 10th 2013) 13 | 14 | Entity editing: 15 | 16 | * Terminology: _midgardEditable_ is now known as an _editable entity widget_, and the editors it runs for various properties are known as _property editor widgets_ 17 | * Entity editing widget now accepts two callbacks for instantiating decorators for entities and their properties in the DOM. This is handy for CMSs that want to visualize what can be edited 18 | * `decorateEditableEntity` callback is called for the entity loaded to the editable widget 19 | * `decoratePropertyEditor` callback is called for each property of the entity 20 | * Entity editables are now able to run without _VIE Collection view_ being defined 21 | * Events emitted by the editing widgets now carry the new terminology. The old event data keys are still available as fallbacks: 22 | * `entity`: VIE entity instance (Backbone.js model) 23 | * `editableEntity`: _midgardEditable_ widget instance 24 | * `entityElement`: DOM element containing the entity 25 | * Events emitted by the property editing widgets now carry the new terminology. The old event data keys are still available as fallbacks: 26 | * `predicate`: name of the property being edited 27 | * `propertyEditor`: editor instance 28 | * `propertyElement`: DOM element containing the property 29 | * The state model for entity editing was clarified, with the following different states instead of enabled, disabled, and active: 30 | * _Inactive_: editable is loaded but disabled 31 | * _Candidate_: editable is enabled but not activated 32 | * _Highlight_: user is hovering over the editable (not set by Editable widget directly) 33 | * _Activating_: an editor widget is being activated for user to edit with it (skipped for editors that activate instantly) 34 | * _Active_: user is actually editing something inside the editable 35 | * _Changed_: user has made changes to the editable 36 | * _Invalid_: the contents of the editable have validation errors 37 | * The `modified` event was renamed to `changed` to follow the new states 38 | * New public methods `setState` and `getState` were added for manipulating the state from the application controller 39 | * States are passed as strings corresponding to the new editing states (for example, `inactive` or `changed`) 40 | * The `setState` method has an optional `predicate` parameter for targeting a particular property editor with the state change 41 | * New Rich Text Editors 42 | * [CKEditor](http://ckeditor.com/) 4 43 | * TinyMCE 4 44 | 45 | Metadata editing: 46 | 47 | * New _midgardMetadata_ widget was added to act as the controller for all different metadata editors 48 | * _midgardTags_ was refactored to run inside the metadata editing widget 49 | 50 | This changes tags initialization from: 51 | 52 | ``` javascript 53 | jQuery('body').midgardCreate({ 54 | tags: true 55 | }); 56 | ``` 57 | 58 | to: 59 | 60 | ``` javascript 61 | jQuery('body').midgardCreate({ 62 | metadata: { 63 | midgardTags: {} 64 | } 65 | }); 66 | ``` 67 | 68 | Storage: 69 | 70 | * The `revertChanges` method was made public, allowing external UIs to trigger reverting entities to their original states 71 | * The `hasLocal` and `readLocal` methods were made public to allow manipulating localStorage from the application controller 72 | * The `saveRemote` method was made public, allowing the application controller to trigger saving for a single entity 73 | * new `save` and `saved` events are triggered for the whole set of entities being saved 74 | * new `saveentity` and `savedentity` events are triggered for each entity being saved 75 | * Options used when calling `saveRemote` are now passed on in the save-related events 76 | * key prefix used with localStorage is now configurable 77 | 78 | Create.js internals: 79 | 80 | * The whole library has been migrated to use jQuery [`on` and `off`](http://api.jquery.com/category/events/event-handler-attachment/) methods instead of `bind` and `unbind` 81 | * All widgets were migrated to the *Midgard* namespace to maintain consistency 82 | * Switched to Grunt for builds 83 | * Switched to Bower for dependency handling 84 | * Moved built version to `dist/create.js` 85 | * New build option for creating a smaller edit-only version of Create.js: `$ grunt editonly` 86 | * The build process was improved to work also on Mac OS X 87 | 88 | Dependencies: 89 | 90 | * [VIE](https://github.com/bergie/VIE) was updated to 2.1.0 91 | * [Hallo](https://github.com/bergie/hallo) was updated to the latest git version 92 | * [jQuery-Tags-Input](https://github.com/xoxco/jQuery-Tags-Input) -- used by the _midgardTags_ widget -- was updated to latest git version 93 | * jQuery was updated to version 1.9.1 and jQuery UI to version 1.10.2. Some compatibiity work still remains 94 | 95 | Development: 96 | 97 | * The build environment of Create.js was switched to [Grunt](http://gruntjs.com) 98 | 99 | Localization: 100 | 101 | * Hebrew and Romanian translations were added 102 | 103 | _Thanks to the [Drupal Edit](http://drupal.org/project/edit) team for major contributions to this release!_ 104 | 105 | ## 1.0.0alpha3 (September 27th 2012) 106 | 107 | Collection editing: 108 | 109 | * _Add_ buttons are now shown only for collections VIE is able to add views for 110 | * New _midgardCollectionAddBetween_ widget for more flexible collection editing 111 | * Collection widgets are now able to [ask the user for the type](http://bergie.iki.fi/blog/create-collections/) to add in case of collections that can multiple types inside them 112 | * Collection widgets are aware of possible size constraints in VIE collections. If a collection is full, the _Add_ buttons are not shown 113 | 114 | User interface: 115 | 116 | * Support for keyboard shortcuts if the [Mousetrap](https://github.com/ccampbell/mousetrap) library is available: 117 | * _Ctrl-e_: enter editing mode 118 | * _Esc_: leave editing mode 119 | * _Ctrl-s_: save changes 120 | * _Ctrl-Shift-i_: ignore local modifications (when entering edit mode) 121 | * _Ctrl-Shift-r_: revert to local modifications (when entering edit mode) 122 | 123 | Localization: 124 | 125 | * Support for localizing the Create.js user interface. You can pass custom localization callbacks using the `localize` option of the widgets 126 | * First batch of languages: 127 | * Swedish 128 | * Bulgarian 129 | * Spanish 130 | * Czech 131 | * Russian 132 | * Polish 133 | * Dutch 134 | * Danish 135 | * Italian 136 | * Norwegian 137 | * German 138 | * French 139 | * Brazilian Portuguese 140 | * Finnish 141 | 142 | Storage: 143 | 144 | * Autosaving now saves changes using Backbone's `silent` option so that it doesn't modify the DOM elements user is editing 145 | * The `checkRestore` method was made public to allow external web applications to restore content 146 | * The `saveRemoteAll` method was made public 147 | 148 | Create.js internals: 149 | 150 | * The VIE DOM service used with Create.js is now configurable. You can replace the default _RDFa Service_ with your own implementation to support custom mark-up 151 | * The custom DOM service can be passed via the `domService` key of Create.js widget options 152 | * All Create.js code is now being run in [JavaScript strict mode](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Functions_and_function_scope/Strict_mode) 153 | * Continuous Integration of Create.js was switched to using PhantomJS with QUnit 154 | * Create's HTML output was changed to use [Underscore Templates](http://underscorejs.org/#template) for better configurability 155 | 156 | Dependencies: 157 | 158 | * [VIE](https://github.com/bergie/VIE) was updated to latest git version 159 | * [Hallo](https://github.com/bergie/hallo) was updated to the latest git version 160 | * Hallo now depends on the [Rangy](http://code.google.com/p/rangy/) library 161 | * The [Modernizr](http://modernizr.com/) dependency was removed 162 | 163 | _Thanks to the [TYPO3 Neos](http://neos.typo3.org/) team for great collaboration on this release! We're also grateful for the translation contributions from all around the world._ 164 | -------------------------------------------------------------------------------- /Gruntfile.coffee: -------------------------------------------------------------------------------- 1 | module.exports = -> 2 | banner = """/* Create.js <%= pkg.version %> - Inline editing toolkit 3 | by Henri Bergius and contributors. Available under the MIT license. 4 | See http://createjs.org for more information 5 | */""" 6 | 7 | # Project configuration 8 | @initConfig 9 | pkg: @file.readJSON 'package.json' 10 | 11 | # Install dependencies 12 | 'bower-install-simple': 13 | deps: 14 | options: 15 | interactive: false 16 | forceLatest: false 17 | directory: 'bower_components' 18 | 19 | # Build setup: concatenate source files 20 | concat: 21 | options: 22 | stripBanners: true 23 | banner: banner 24 | full: 25 | src: [ 26 | 'src/*.js' 27 | 'src/**/*.js' 28 | 'locale/*.js' 29 | ] 30 | dest: 'dist/create.js' 31 | edit: 32 | src: [ 33 | 'src/jquery.Midgard.midgardEditable.js' 34 | 'src/jquery.Midgard.midgardStorage.js' 35 | 'src/collectionWidgets/*.js' 36 | 'src/editingWidgets/*.js' 37 | ] 38 | dest: 'dist/create-editonly.js' 39 | 40 | # JavaScript minification 41 | uglify: 42 | options: 43 | banner: banner 44 | report: 'min' 45 | full: 46 | files: 47 | 'dist/create.min.js': ['dist/create.js'] 48 | edit: 49 | files: 50 | 'dist/create-editonly.min.js': ['dist/create-editonly.js'] 51 | 52 | 53 | # Coding standards verification 54 | jshint: 55 | all: ['src/*.js', 'src/**/*.js', 'locale/*.js'] 56 | 57 | # Unit tests 58 | qunit: 59 | all: ['test/*.html'] 60 | 61 | # Cross-browser testing 62 | connect: 63 | server: 64 | options: 65 | base: '' 66 | port: 9999 67 | 68 | 'saucelabs-qunit': 69 | all: 70 | options: 71 | urls: ['http://127.0.0.1:9999/test/index.html'] 72 | browsers: [ 73 | browserName: 'chrome' 74 | , 75 | browserName: 'safari' 76 | platform: 'OS X 10.9' 77 | version: '7' 78 | , 79 | browserName: 'internet explorer' 80 | platform: 'Windows 8.1', 81 | version: '11' 82 | ] 83 | build: process.env.TRAVIS_JOB_ID 84 | testname: 'Create.js cross-browser tests' 85 | tunnelTimeout: 5 86 | concurrency: 1 87 | detailedError: true 88 | 89 | # Dependency installation 90 | @loadNpmTasks 'grunt-bower-install-simple' 91 | 92 | # Build dependencies 93 | @loadNpmTasks 'grunt-contrib-concat' 94 | @loadNpmTasks 'grunt-contrib-uglify' 95 | 96 | # Testing dependencies 97 | @loadNpmTasks 'grunt-contrib-jshint' 98 | @loadNpmTasks 'grunt-contrib-qunit' 99 | 100 | # Cross-browser testing 101 | @loadNpmTasks 'grunt-contrib-connect' 102 | @loadNpmTasks 'grunt-saucelabs' 103 | 104 | # Local tasks 105 | @registerTask 'build', ['bower-install-simple', 'concat:full', 'uglify:full'] 106 | @registerTask 'editonly', ['concat:edit', 'uglify:edit'] 107 | @registerTask 'test', ['jshint', 'build', 'qunit'] 108 | @registerTask 'crossbrowser', ['test', 'connect', 'saucelabs-qunit'] 109 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Henri Bergius, The Midgard Project 2 | 3 | Permission is hereby granted, free of charge, to any person 4 | obtaining a copy of this software and associated documentation 5 | files (the "Software"), to deal in the Software without 6 | restriction, including without limitation the rights to use, 7 | copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following 10 | conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 17 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 19 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 20 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 | OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Create - On-site web editing interface [![Build Status](https://secure.travis-ci.org/bergie/create.png)](http://travis-ci.org/bergie/create) [![Greenkeeper badge](https://badges.greenkeeper.io/bergie/create.svg)](https://greenkeeper.io/) 2 | ====================================== 3 | 4 | ![Create logo](https://github.com/bergie/create/raw/master/design/create.png) 5 | 6 | Create, from the [Midgard Project](http://www.midgard-project.org/), is a comprehensive web editing interface for Content Management Systems. It is designed to provide a modern, fully browser-based HTML5 environment for managing content. Create can be adapted to work on almost any content management backend. 7 | 8 | ![Midgard Create user interface, in March 2011](http://bergie.iki.fi/files/1e045994d03c25e459911e0ab235550c1aac901c901_midgardcreate-enter-edit-state-small.png) ![Midgard Create user interface, in March 2011](http://bergie.iki.fi/files/1e04599abfee694459911e0bf1021b4fddbed1bed1b_midgardcreate-save-transition-small.png) 9 | 10 | Create.js is built on top of [VIE](http://viejs.org), the semantic interaction library powered by Backbone.js. The widgets in Create.js itself are done with the jQuery UI tools. 11 | 12 | [![Cross-browser testing status](https://saucelabs.com/browser-matrix/create-js.svg)](https://saucelabs.com/u/create-js) 13 | 14 | ## Features 15 | 16 | * Making RDFa-annotated content on pages editable 17 | * Managing collections of content (add, remove) 18 | * Local, in-browser storage and retrieval of unsaved content 19 | * Adaptable connector for communicating with the back-end system 20 | * Running workflows (approval, etc.) for content items 21 | * Browsing and reverting content history 22 | * Easy rebranding of the interface with some CSS 23 | * Can be used as-is, or as a toolkit for a custom CMS UI 24 | 25 | ## Integrating Create with your CMS 26 | 27 | Please refer to the [Create.js Integration Guide](http://createjs.org/guide/). 28 | 29 | PHP developers should also check out [CreatePHP](https://github.com/flack/createphp). For easier Node.js integration there is [contentblocks](https://github.com/primaryobjects/contentblocks). 30 | 31 | ## Future plans 32 | 33 | * Adopt the [Web Intents](http://webintents.org/) specification for better image and link handling 34 | * Content annotation and auto-tagging with [Apache Stanbol](http://incubator.apache.org/stanbol/) 35 | * Wrapper for using Create inside [Google Web Toolkit](http://code.google.com/webtoolkit/) via [VIE-GWT](https://github.com/alkacon/vie-gwt) 36 | 37 | ## Dependencies 38 | 39 | * [Hallo](http://bergie.github.com/hallo/) - distraction-free content editor (optionally, [Aloha Editor](http://aloha-editor.org/) or [Redactor](http://redactorjs.com/)) 40 | * [VIE](https://github.com/bergie/vie) - editable RDFa library 41 | * [Backbone.js](http://documentcloud.github.com/backbone/) - client-side management of models, views, and collections 42 | * [jQuery UI](http://jqueryui.com/) - widget and effect library 43 | * [Mousetrap](http://craig.is/killing/mice) - keyboard shortcuts library (optional) 44 | 45 | ## Building Create 46 | 47 | Create.js uses a build system running on [Node.js](http://nodejs.org/), so you'll need that. Install the build dependencies with: 48 | 49 | $ npm install 50 | 51 | Use the supplied `Gruntfile.coffee` to generate the merged JavaScript file for Create: 52 | 53 | $ grunt build 54 | 55 | You can also generate a simplified version that only includes the inline editing features: 56 | 57 | $ grunt editonly 58 | 59 | Note: the `grunt` command is part of the [Grunt](http://gruntjs.com) package. You can either run it from `./node_modules/.bin/grunt` or install it globally via `npm install -g grunt-cli`. 60 | 61 | ## Read more 62 | 63 | * [Introducing the Midgard Create user interface](http://bergie.iki.fi/blog/introducing_the_midgard_create_user_interface/) 64 | * [Using RDFa to make a web page editable](http://bergie.iki.fi/blog/using_rdfa_to_make_a_web_page_editable/) 65 | * [Midgard Create and VIE presentation in the Aloha Editor conference](http://bergie.iki.fi/blog/midgard_create_and_vie_in_the_aloha_editor_conference/) 66 | 67 | ## Discussion 68 | 69 | * [Create.js Google Groups mailing list](http://groups.google.com/group/createjs) 70 | * [`#iks` IRC channel on Freenode](irc://irc.freenode.net/iks) 71 | 72 | ## Similar projects 73 | 74 | * [Etch](http://etchjs.com/) 75 | 76 | ## Editor alternatives 77 | 78 | The default rich text editor shipping with Create is [Hallo](http://hallojs.org/), an MIT-licensed editing widget. 79 | 80 | You can also use other editor options under their own licensing schemes, or integrate something else. 81 | 82 | ### Using Aloha Editor 83 | 84 | By default, Create uses the [Hallo Editor](http://bergie.github.com/hallo/). To use Create with [Aloha Editor](http://aloha-editor.org/) you need to: 85 | 86 | * [Download the latest version of Aloha Editor](http://aloha-editor.org/builds/development/latest.zip) 87 | * Extract the archive file and move the `aloha` directory into the `create/deps` folder -- check to have it like this: `create/deps/aloha/lib/aloha.js` 88 | * For more information about using Aloha Editor see the [Aloha Editor Guides](http://aloha-editor.org/builds/development/latest/doc/guides/output/) 89 | 90 | Using Aloha Editor with Create is covered by Aloha's FOSS License Exception: 91 | 92 | > Aloha Editor’s Free and Open Source Software ("FOSS") License Exception allows developers of FOSS applications to include Aloha Editor with their FOSS applications. Aloha Editor is typically licensed pursuant to version 3 of the General Afero Public License ("AGPLv3"), but this exception permits distribution of Aloha Editor with a developer’s FOSS applications licensed under the terms of another FOSS license listed below [MIT license is included], even though such other FOSS license may be incompatible with the AGPLv3. 93 | 94 | ### Using Redactor 95 | 96 | You need to acquire a [Redactor license](http://redactorjs.com/license/) and include the editor JavaScript and CSS files into your pages separately. Then you can set Create to use Redactor for particular areas by using the `redactorWidget` editor option. 97 | 98 | ## Translations 99 | 100 | The whole Create.js user interface can be translated to different languages. 101 | 102 | To contribute a translation, copy the [English localization file](https://github.com/bergie/create/blob/master/locale/en.js) and replace the values there with your language. Then send the file via a pull request. 103 | 104 | Changes to strings used by Create.js will be announced on the [mailing list](http://groups.google.com/group/createjs), so it is a good idea to subscribe to it if you make translations. 105 | 106 | ### Running Unit Tests in browser 107 | 108 | Direct your browser to the `test/index.html` file to run Create's [QUnit](http://docs.jquery.com/Qunit) tests. 109 | 110 | #### Headless unit tests on PhantomJS 111 | 112 | PhantomJS test automation is part of the project's build configuration: 113 | 114 | $ grunt test 115 | 116 | or: 117 | 118 | $ npm test 119 | 120 | #### Continuous integration 121 | 122 | Create uses [Travis](http://travis-ci.org/) for continuous integration. Simply add your fork there and every time you push you'll get the tests run. See [our Travis build page](http://travis-ci.org/#!/bergie/create) for more information. 123 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "create", 3 | "main": "./dist/create.js", 4 | "license": "MIT", 5 | "ignore": [ 6 | "**/.*", 7 | "node_modules", 8 | "bower_components", 9 | "components", 10 | "nodejs", 11 | "deps", 12 | "lib" 13 | ], 14 | "dependencies": { 15 | "jquery": "1.9.x", 16 | "jquery-ui": "1.10.x", 17 | "vie": "2.2.x", 18 | "backbone": "1.0.0", 19 | "underscore": "1.6.0", 20 | "jquery.tagsinput": "1.3.x", 21 | "annotate": "0.0.x", 22 | "hallo": "1.1.x" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /design/create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/design/create.png -------------------------------------------------------------------------------- /design/create.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 41 | 43 | 44 | 46 | image/svg+xml 47 | 49 | 50 | 51 | 52 | 53 | 57 | 62 | 67 | Create 83 | 84 | -------------------------------------------------------------------------------- /examples/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-left: 20%; 3 | padding-right: 20%; 4 | padding-top: 50px; 5 | background-color: #eeeeec; 6 | } 7 | 8 | article h1, h2 { 9 | font-family: "Georgia", serif; 10 | font-variant: small-caps; 11 | margin-bottom: 0px; 12 | padding-bottom: 0.5em; 13 | } 14 | 15 | article h1 { 16 | font-size: 24pt; 17 | } 18 | 19 | article h2 { 20 | font-size: 20pt; 21 | } 22 | 23 | article p { 24 | margin-top: 0px; 25 | margin-bottom: 0.5em; 26 | text-indent: 2em; 27 | } 28 | 29 | section { 30 | display: block; 31 | min-height: 1em; 32 | } 33 | 34 | .sections > section { 35 | clear: left; 36 | } 37 | 38 | .sections > button { 39 | clear: left; 40 | } 41 | 42 | .multicolumn > section { 43 | width: 48%; 44 | float: left; 45 | } 46 | -------------------------------------------------------------------------------- /examples/example-aloha.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example with Aloha Editor 6 | 7 | 8 | 9 | 10 | 11 | 37 | 38 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
59 |
60 | 61 |

News item title

62 |
63 |

64 | Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. 65 |

66 |

67 | Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum. 68 |

69 |
70 | 71 |
72 | 73 |
74 |

Another item

75 |
76 |

Aloha, world!

77 |
78 |
79 | 80 |
81 | 82 | 83 | 84 | 85 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /examples/example-ckeditor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example with CKEditor 4 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | 48 |
50 |
51 |

News item title

52 |
Henri Bergius
53 |
54 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

55 |

Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

56 |
57 | 60 |
61 |
62 |

Another item

63 |
64 |

Hello, world!

65 |
66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/example-geo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 68 | 70 | 72 | 74 | 75 | 76 | 77 | 78 |
79 |

c-base Spacestation

80 |
81 | Die Raumstation c-base geriet nach Erkenntnissen der Vereinsmitglieder einst in ein Zeitloch und stürzte aufgrund der schlagartig veränderten Bedingungen aus einer fernen Zukunft auf die Erde ab. An Bord befanden sich eine Reihe hochtechnologischer Entwicklungen und noch nicht erforschte Lebensformen. 82 | Im heutigen Berlin sind angeblich zahlreiche „Belege“ für die Existenz der Raumstation zu finden. Vor allem die Antenne der Station, die heute als Fernsehturm genutzt wird, ist seit ihrer Enttarnung durch Wissenschaftler der DDR und der Sowjetunion weithin sichtbar im Stadtbild Berlins. Andere Orte, wie die beim Absturz abgesprengte „Multimodulstation“ (derzeit der aktuelle Ort des Vereins), unterliegen gerade erst einer ausgiebigen Erforschung. 83 | Das aktuelle Wissen um die c-base ist im so genannten Allmanach niedergeschrieben, der allerdings bislang nur in gedruckter Form vorliegt. Die c-pedia versucht als Online-Enzyklopädie das angesammelte Wissen auch im Internet verfügbar zu machen, steht aber derzeit noch am Anfang. Daneben wird auch die „Rekonstruktion von Artefakten der c-base“ vorangetrieben. 84 |
85 |
86 |
87 | 52.51301667140004 88 | 13.4201287460338 89 |
90 |
91 |
92 | 93 | 94 | -------------------------------------------------------------------------------- /examples/example-medium.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example with Medium Editor 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | 48 | 49 |
51 |
52 |

News item title

53 |
Henri Bergius
54 |
55 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

56 |

Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

57 |
58 |
59 |
60 |

Another item

61 |
62 |

Hello, world!

63 |
64 |
65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /examples/example-redactor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 47 | 49 | 51 | 53 | 54 | 55 | 56 | 57 |
59 |
60 |

News item title

61 |
Henri Bergius
62 |
63 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

64 |

Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

65 |
66 |
67 |
68 |

Another item

69 |
70 |

Hello, world!

71 |
72 |
73 |
74 | 75 | 76 | -------------------------------------------------------------------------------- /examples/example-tinymce.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example with TinyMCE 4 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 38 | 40 | 42 | 44 | 45 | 46 | 47 | 48 |
50 |
51 |

News item title

52 |
Henri Bergius
53 |
54 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

55 |

Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

56 |
57 | 60 |
61 |
62 |

Another item

63 |
64 |

Hello, world!

65 |
66 |
67 |
68 | 69 | 70 | -------------------------------------------------------------------------------- /examples/example-withtype.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create type-based example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 29 | 35 | 131 | 133 | 135 | 137 | 138 | 139 | 140 | 141 | 142 |
143 |

My page title

144 |
Henri Bergius
145 |
146 |
147 |
148 | 149 | 150 | -------------------------------------------------------------------------------- /examples/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Midgard Create example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 58 | 60 | 62 | 64 | 65 | 66 | 67 | 68 |
70 |
71 |

News item title

72 |
Henri Bergius
73 |
74 |

Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.

75 |

Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc nobis videntur parum clari, fiant sollemnes in futurum.

76 |
77 | 80 |
81 |
82 |

Another item

83 |
84 |

Hello, world!

85 |
86 |
87 |
88 | 89 | 90 | -------------------------------------------------------------------------------- /examples/font-awesome/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/examples/font-awesome/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /examples/font-awesome/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/examples/font-awesome/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /examples/font-awesome/fonts/fontawesome-webfont.svgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/examples/font-awesome/fonts/fontawesome-webfont.svgz -------------------------------------------------------------------------------- /examples/font-awesome/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/examples/font-awesome/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /examples/font-awesome/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/examples/font-awesome/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /locale/locale_bg.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.bg = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Запази', 11 | 'Saving': 'Запазване', 12 | 'Cancel': 'Откажи', 13 | 'Edit': 'Редактирай', 14 | // Storage status messages 15 | 'localModification': 'Елементът "<%= label %>" има локални модификации', 16 | 'localModifications': '<%= number %> елемента на тази страница имат локални модификации', 17 | 'Restore': 'Възстанови', 18 | 'Ignore': 'Игнорирай', 19 | 'saveSuccess': 'Елементът "<%= label %>" беше успешно запазен', 20 | 'saveSuccessMultiple': '<%= number %> елемента бяха успешно запазени', 21 | 'saveError': 'Възника грешка при запазване
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Етикети на елемента', 24 | 'Suggested tags': 'Препоръчани етикети', 25 | 'Tags': 'Етикети', 26 | 'add a tag': 'добави етикет', 27 | // Collection widgets 28 | 'Add': 'Добави', 29 | 'Choose type to add': 'Избери тип за добавяне' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_cs.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.cs = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Uložit', 11 | 'Saving': 'Probíhá ukládání', 12 | 'Cancel': 'Zrušit', 13 | 'Edit': 'Upravit', 14 | // Storage status messages 15 | 'localModification': 'Blok "<%= label %>" obsahuje lokální změny', 16 | 'localModifications': '<%= number %> bloků na této stránce má lokální změny', 17 | 'Restore': 'Aplikovat lokální změny', 18 | 'Ignore': 'Zahodit lokální změny', 19 | 'saveSuccess': 'Blok "<%= label %>" byl úspěšně uložen', 20 | 'saveSuccessMultiple': '<%= number %> bloků bylo úspěšně uloženo', 21 | 'saveError': 'Při ukládání došlo k chybě
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Štítky bloku', 24 | 'Suggested tags': 'Navrhované štítky', 25 | 'Tags': 'Štítky', 26 | 'add a tag': 'Přidat štítek', 27 | // Collection widgets 28 | 'Add': 'Přidat', 29 | 'Choose type to add': 'Vyberte typ k přidání' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_da.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.da = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Gem', 11 | 'Saving': 'Gemmer', 12 | 'Cancel': 'Annullér', 13 | 'Edit': 'Rediger', 14 | // Storage status messages 15 | 'localModification': 'Element "<%= label %>" har lokale ændringer', 16 | 'localModifications': '<%= number %> elementer på denne side har lokale ændringer', 17 | 'Restore': 'Gendan', 18 | 'Ignore': 'Ignorer', 19 | 'saveSuccess': 'Element "<%= label %>" er gemt', 20 | 'saveSuccessMultiple': '<%= number %> elementer er gemt', 21 | 'saveError': 'Der opstod en fejl under lagring
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Element tags', 24 | 'Suggested tags': 'Foreslåede tags', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'tilføj et tag', 27 | // Collection widgets 28 | 'Add': 'Tilføj', 29 | 'Choose type to add': 'Vælg type der skal tilføjes' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_de.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.de = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Speichern', 11 | 'Saving': 'Speichert', 12 | 'Cancel': 'Abbrechen', 13 | 'Edit': 'Bearbeiten', 14 | // Storage status messages 15 | 'localModification': 'Das Dokument "<%= label %>" auf dieser Seite hat lokale Änderungen', 16 | 'localModifications': '<%= number %> Dokumente auf dieser Seite haben lokale Änderungen', 17 | 'Restore': 'Wiederherstellen', 18 | 'Ignore': 'Ignorieren', 19 | 'saveSuccess': 'Dokument "<%= label %>" erfolgreich gespeichert', 20 | 'saveSuccessMultiple': '<%= number %> Dokumente erfolgreich gespeichert', 21 | 'saveError': 'Fehler beim Speichern
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Schlagwörter des Dokuments', 24 | 'Suggested tags': 'Schlagwortvorschläge', 25 | 'Tags': 'Schlagwörter', 26 | 'add a tag': 'Neues Schlagwort', 27 | // Collection widgets 28 | 'Add': 'Hinzufügen', 29 | 'Choose type to add': 'Typ zum Hinzufügen wählen' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_en.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.en = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Save', 11 | 'Saving': 'Saving', 12 | 'Cancel': 'Cancel', 13 | 'Edit': 'Edit', 14 | // Storage status messages 15 | 'localModification': 'Item "<%= label %>" has local modifications', 16 | 'localModifications': '<%= number %> items on this page have local modifications', 17 | 'Restore': 'Restore', 18 | 'Ignore': 'Ignore', 19 | 'saveSuccess': 'Item "<%= label %>" saved successfully', 20 | 'saveSuccessMultiple': '<%= number %> items saved successfully', 21 | 'saveError': 'Error occurred while saving
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Item tags', 24 | 'Suggested tags': 'Suggested tags', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'add a tag', 27 | // Collection widgets 28 | 'Add': 'Add', 29 | 'Choose type to add': 'Choose type to add' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_es.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.es = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Guardar', 11 | 'Saving': 'Guardando', 12 | 'Cancel': 'Cancelar', 13 | 'Edit': 'Editar', 14 | // Storage status messages 15 | 'localModification': 'El elemento "<%= label %>" tiene modificaciones locales', 16 | 'localModifications': '<%= number %> elementos en la página tienen modificaciones locales', 17 | 'Restore': 'Restaurar', 18 | 'Ignore': 'Ignorar', 19 | 'saveSuccess': 'El elemento "<%= label %>" se guardó exitosamente', 20 | 'saveSuccessMultiple': '<%= number %> elementos se guardaron exitosamente', 21 | 'saveError': 'Ha ocurrido un error cuando se guardaban los datos
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Etiquetas de los elementos', 24 | 'Suggested tags': 'Etiquetas sugeridas', 25 | 'Tags': 'Etiquetas', 26 | 'add a tag': 'añadir una etiqueta', 27 | // Collection widgets 28 | 'Add': 'Añadir', 29 | 'Choose type to add': 'Escoge el tipo a añadir' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_fi.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.fi = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Tallenna', 11 | 'Saving': 'Tallennetaan', 12 | 'Cancel': 'Peruuta', 13 | 'Edit': 'Muokkaa', 14 | // Storage status messages 15 | 'localModification': 'Dokumentilla "<%= label %>" on paikallisia muutoksia', 16 | 'localModifications': '<%= number %> dokumenttia sivulla omaa paikallisia muutoksia', 17 | 'Restore': 'Palauta', 18 | 'Ignore': 'Poista', 19 | 'saveSuccess': 'Dokumentti "<%= label %>" tallennettu', 20 | 'saveSuccessMultiple': '<%= number %> dokumenttia tallennettu', 21 | 'saveError': 'Virhe tallennettaessa
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Avainsanat', 24 | 'Suggested tags': 'Ehdotukset', 25 | 'Tags': 'Avainsanat', 26 | 'add a tag': 'lisää avainsana', 27 | // Collection widgets 28 | 'Add': 'Lisää', 29 | 'Choose type to add': 'Mitä haluat lisätä?' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_fr.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.fr = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Enregistrer', 11 | 'Saving': 'Enregistrement en cours', 12 | 'Cancel': 'Annuler', 13 | 'Edit': 'Éditer', 14 | // Storage status messages 15 | 'localModification': 'L\'élément "<%= label %>" comporte des modifications locales', 16 | 'localModifications': '<%= number %> éléments sur cette page comportent des modifications locales', 17 | 'Restore': 'Restaurer', 18 | 'Ignore': 'Ignorer', 19 | 'saveSuccess': 'L\'élément "<%= label %>" a été enregistré avec succès', 20 | 'saveSuccessMultiple': '<%= number %> éléments ont été enregistrés avec succès', 21 | 'saveError': 'Une erreur est survenue durant l\'enregistrement
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Tags des éléments', 24 | 'Suggested tags': 'Tags suggérés', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'ajouter un tag', 27 | // Collection widgets 28 | 'Add': 'Ajouter', 29 | 'Choose type to add': 'Choisir le type à ajouter' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_he.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.he = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'שמור', 11 | 'Saving': 'שומר', 12 | 'Cancel': 'בטל', 13 | 'Edit': 'ערוך', 14 | // Storage status messages 15 | 'localModification': 'לפריט "<%= label %>" שינויים מקומיים', 16 | 'localModifications': 'ל<%= number %> פריטים בדף זה שינויים מקומיים', 17 | 'Restore': 'שחזר', 18 | 'Ignore': 'התעלם', 19 | 'saveSuccess': 'פריט "<%= label %>" נשמר בהצלחה', 20 | 'saveSuccessMultiple': '<%= number %> פריטים נשמרו בהצלחה', 21 | 'saveError': 'שגיאה בשמירה
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'סיווגי פריט', 24 | 'Suggested tags': 'סיווגים מומלצים', 25 | 'Tags': 'סיווגים', 26 | 'add a tag': 'הוסף סיווג', 27 | // Collection widgets 28 | 'Add': 'הוסף', 29 | 'Choose type to add': 'בחר סוג להוספה' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_it.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.it = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Salva', 11 | 'Saving': 'Salvataggio', 12 | 'Cancel': 'Esci', 13 | 'Edit': 'Modifica', 14 | // Storage status messages 15 | 'localModification': 'Articolo "<%= label %>" in questa pagina hanno modifiche locali', 16 | 'localModifications': '<%= number %> articoli in questa pagina hanno modifiche locali', 17 | 'Restore': 'Ripristina', 18 | 'Ignore': 'Ignora', 19 | 'saveSuccess': 'Articolo "<%= label %>" salvato con successo', 20 | 'saveSuccessMultiple': '<%= number %> articoli salvati con successo', 21 | 'saveError': 'Errore durante il salvataggio
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Tags articolo', 24 | 'Suggested tags': 'Tags suggerite', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'Aggiungi una parola chiave', 27 | // Collection widgets 28 | 'Add': 'Aggiungi', 29 | 'Choose type to add': 'Scegli il tipo da aggiungere' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_lt.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.lt = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Saugoti', 11 | 'Saving': 'Saugojama', 12 | 'Cancel': 'Atšaukti', 13 | 'Edit': 'Redaguoti', 14 | // Storage status messages 15 | 'localModification': 'Įrašas "<%= label %>" turi neišsaugotų pakeitimų', 16 | 'localModifications': '<%= number %> įrašų šiame puslapyje turi lokalių pakeitimų', 17 | 'Restore': 'Atkurti', 18 | 'Ignore': 'Ignoruoti', 19 | 'saveSuccess': 'Įrašas "<%= label %>" sėkmingai išsaugotas', 20 | 'saveSuccessMultiple': '<%= number %> elementų sėkmingai išsaugota', 21 | 'saveError': 'Klaida išsaugojant
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Įrašo žymos', 24 | 'Suggested tags': 'Siūlomos žymos', 25 | 'Tags': 'Žymos', 26 | 'add a tag': 'pridėti žymą', 27 | // Collection widgets 28 | 'Add': 'Pridėti', 29 | 'Choose type to add': 'Pasirinkite pridedamą tipą' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_nl.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.nl = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Opslaan', 11 | 'Saving': 'Bezig met opslaan', 12 | 'Cancel': 'Annuleren', 13 | 'Edit': 'Bewerken', 14 | // Storage status messages 15 | 'localModification': 'Items "<%= label %>" op de pagina heeft lokale wijzigingen', 16 | 'localModifications': '<%= number %> items op de pagina hebben lokale wijzigingen', 17 | 'Restore': 'Herstellen', 18 | 'Ignore': 'Negeren', 19 | 'saveSuccess': 'Item "<%= label %>" succesvol opgeslagen', 20 | 'saveSuccessMultiple': '<%= number %> items succesvol opgeslagen', 21 | 'saveError': 'Fout opgetreden bij het opslaan
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Item tags', 24 | 'Suggested tags': 'Tag suggesties', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'tag toevoegen', 27 | // Collection widgets 28 | 'Add': 'Toevoegen', 29 | 'Choose type to add': 'Kies type om toe te voegen' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_no.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.no = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Lagre', 11 | 'Saving': 'Lagrer', 12 | 'Cancel': 'Avbryt', 13 | 'Edit': 'Rediger', 14 | // Storage status messages 15 | 'localModification': 'Element "<%= label %>" på denne siden er modifisert lokalt', 16 | 'localModifications': '<%= number %> elementer på denne siden er modifisert lokalt', 17 | 'Restore': 'Gjenopprett', 18 | 'Ignore': 'Ignorer', 19 | 'saveSuccess': 'Element "<%= label %>" ble lagret', 20 | 'saveSuccessMultiple': '<%= number %> elementer ble lagret', 21 | 'saveError': 'En feil oppstod under lagring
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Element-tagger', 24 | 'Suggested tags': 'Anbefalte tagger', 25 | 'Tags': 'Tagger', 26 | 'add a tag': 'legg til tagg', 27 | // Collection widgets 28 | 'Add': 'Legg til', 29 | 'Choose type to add': 'Velg type å legge til' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_pl.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.pl = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Zapisz', 11 | 'Saving': 'Zapisuję', 12 | 'Cancel': 'Anuluj', 13 | 'Edit': 'Edytuj', 14 | // Storage status messages 15 | 'localModification': 'Artykuł "<%= label %>" posiada lokalne modyfikacje', 16 | 'localModifications': '<%= number %> artykułów na tej stronie posiada lokalne modyfikacje', 17 | 'Restore': 'Przywróć', 18 | 'Ignore': 'Ignoruj', 19 | 'saveSuccess': 'Artykuł "<%= label %>" został poprawnie zapisany', 20 | 'saveSuccessMultiple': '<%= number %> artykułów zostało poprawnie zapisanych', 21 | 'saveError': 'Wystąpił błąd podczas zapisywania
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Tagi artykułów', 24 | 'Suggested tags': 'Sugerowane tagi', 25 | 'Tags': 'Tagi', 26 | 'add a tag': 'dodaj tag', 27 | // Collection widgets 28 | 'Add': 'Dodaj', 29 | 'Choose type to add': 'Wybierz typ do dodania' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_pt_BR.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.pt_BR = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Salvar', 11 | 'Saving': 'Salvando', 12 | 'Cancel': 'Cancelar', 13 | 'Edit': 'Editar', 14 | // Storage status messages 15 | 'localModification': 'Item "<%= label %>" nesta página possuem modificações locais', 16 | 'localModifications': '<%= number %> itens nesta página possuem modificações locais', 17 | 'Restore': 'Restaurar', 18 | 'Ignore': 'Ignorar', 19 | 'saveSuccess': 'Item "<%= label %>" salvo com sucesso', 20 | 'saveSuccessMultiple': '<%= number %> itens salvos com sucesso', 21 | 'saveError': 'Erro ocorrido ao salvar
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Tags de item', 24 | 'Suggested tags': 'Tags sugeridas', 25 | 'Tags': 'Tags', 26 | 'add a tag': 'adicionar uma tag', 27 | // Collection widgets 28 | 'Add': 'Adicionar', 29 | 'Choose type to add': 'Selecione o tipo para adicionar' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_ro.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.ro = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Salvează', 11 | 'Saving': 'Se salvează', 12 | 'Cancel': 'Anulează', 13 | 'Edit': 'Editare', 14 | // Storage status messages 15 | 'localModification': 'Zona "<%= label %>" a fost modificată', 16 | 'localModifications': '<%= number %> zone din această pagină au fost modificate', 17 | 'Restore': 'Revenire', 18 | 'Ignore': 'Ignoră', 19 | 'saveSuccess': 'Zona "<%= label %>" a fost salvată', 20 | 'saveSuccessMultiple': '<%= number %> zone au fost salvate', 21 | 'saveError': 'S-a produs o eroare în timpul salvării
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Etichetele zonei', 24 | 'Suggested tags': 'Etichete sugerate', 25 | 'Tags': 'Etichete', 26 | 'add a tag': 'adaugă o etichetă', 27 | // Collection widgets 28 | 'Add': 'Adăugare', 29 | 'Choose type to add': 'Alegeți un tip pentru adăugare' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_ru.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.ru = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Сохранить', 11 | 'Saving': 'Сохраняю', 12 | 'Cancel': 'Отмена', 13 | 'Edit': 'Редактировать', 14 | // Storage status messages 15 | 'localModification': 'В запись "<%= label %>" внесены несохранённые изменения', 16 | 'localModifications': 'В записи на этой странице (<%= number %> шт.) внесены несохранённые изменения', 17 | 'Restore': 'Восстановить', 18 | 'Ignore': 'Игнорировать', 19 | 'saveSuccess': 'Запись "<%= label %>" была успешно сохранена', 20 | 'saveSuccessMultiple': ' Записи (<%= number %> шт.) были успешно сохранены', 21 | 'saveError': 'Во время сохранения произошла ошибка
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Теги записей', 24 | 'Suggested tags': 'Предлагаемые теги', 25 | 'Tags': 'Теги', 26 | 'add a tag': 'добавить тег', 27 | // Collection widgets 28 | 'Add': 'Добавить', 29 | 'Choose type to add': 'Выбрать тип для добавления' 30 | }; 31 | -------------------------------------------------------------------------------- /locale/locale_sv.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | if (window.midgardCreate.locale === undefined) { 5 | window.midgardCreate.locale = {}; 6 | } 7 | 8 | window.midgardCreate.locale.sv = { 9 | // Session-state buttons for the main toolbar 10 | 'Save': 'Spara', 11 | 'Saving': 'Sparar', 12 | 'Cancel': 'Avbryt', 13 | 'Edit': 'Redigera', 14 | // Storage status messages 15 | 'localModification': 'Elementet "<%= label %>" har lokala förändringar', 16 | 'localModifications': '<%= number %> element på den här sidan har lokala förändringar', 17 | 'Restore': 'Återställ', 18 | 'Ignore': 'Ignorera', 19 | 'saveSuccess': 'Elementet "<%= label %>" sparades', 20 | 'saveSuccessMultiple': '<%= number %> element sparades', 21 | 'saveError': 'Ett fel uppstod under sparande
<%= error %>', 22 | // Tagging 23 | 'Item tags': 'Element-taggar', 24 | 'Suggested tags': 'Föreslagna taggar', 25 | 'Tags': 'Taggar', 26 | 'add a tag': 'lägg till en tagg', 27 | // Collection widgets 28 | 'Add': 'Lägg till', 29 | 'Choose type to add': 'Välj typ att lägga till' 30 | }; 31 | -------------------------------------------------------------------------------- /manifest.yml: -------------------------------------------------------------------------------- 1 | version: 0.0.1 2 | authors: 3 | bergie: 4 | name: Henri Bergius 5 | email: henri.bergius@iki.fi 6 | url: http://bergie.iki.fi/ 7 | -------------------------------------------------------------------------------- /nodejs/static.js: -------------------------------------------------------------------------------- 1 | var pathMatcher = new RegExp('^/createjs.org/([a-zA-Z.]+).(css|js)'); 2 | var fs = require('fs'); 3 | 4 | exports.static = function() { 5 | return function(req, res, next) { 6 | var matched = pathMatcher.exec(req.url); 7 | if (!matched) { 8 | return next(); 9 | } 10 | 11 | if (matched[2] === 'js') { 12 | var path = __dirname + '/../src/' + matched[1] + '.js'; 13 | fs.readFile(path, 'utf-8', function(err, data) { 14 | if (err) { 15 | next(err); 16 | return; 17 | } 18 | res.writeHead(200, { 19 | 'Content-Type': 'application/javascript' 20 | }); 21 | res.end(data); 22 | }); 23 | return; 24 | } 25 | 26 | next(); 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@bergie/create", 3 | "version": "1.0.0beta1", 4 | "url": "http://createjs.org/", 5 | "author": "Henri Bergius ", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "git://github.com/bergie/create.git" 10 | }, 11 | "dependencies": {}, 12 | "devDependencies": { 13 | "grunt": "~1.0.1", 14 | "grunt-contrib-uglify": "~3.4.0", 15 | "grunt-contrib-concat": "~1.0.1", 16 | "grunt-contrib-jshint": "~1.1.0", 17 | "grunt-contrib-qunit": "~2.0.0", 18 | "grunt-contrib-connect": "~1.0.2", 19 | "grunt-saucelabs": "^9.0.0", 20 | "grunt-bower-install-simple": "^1.0.2" 21 | }, 22 | "scripts": { 23 | "test": "grunt test" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/collectionWidgets/jquery.Midgard.midgardCreateCollectionAdd.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2011-2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false console:false */ 11 | 'use strict'; 12 | 13 | // # Widget for adding items to a collection 14 | jQuery.widget('Midgard.midgardCollectionAdd', { 15 | options: { 16 | editingWidgets: null, 17 | collection: null, 18 | model: null, 19 | definition: null, 20 | view: null, 21 | disabled: false, 22 | vie: null, 23 | editableOptions: null, 24 | templates: { 25 | button: '' 26 | } 27 | }, 28 | 29 | _create: function () { 30 | this.addButtons = []; 31 | var widget = this; 32 | if (!widget.options.collection.localStorage) { 33 | try { 34 | widget.options.collection.url = widget.options.model.url(); 35 | } catch (e) { 36 | if (window.console) { 37 | console.log(e); 38 | } 39 | } 40 | } 41 | 42 | widget.options.collection.on('add', function (model) { 43 | model.primaryCollection = widget.options.collection; 44 | widget.options.vie.entities.add(model); 45 | model.collection = widget.options.collection; 46 | }); 47 | 48 | // Re-check collection constraints 49 | widget.options.collection.on('add remove reset', widget.checkCollectionConstraints, widget); 50 | 51 | widget._bindCollectionView(widget.options.view); 52 | }, 53 | 54 | _bindCollectionView: function (view) { 55 | var widget = this; 56 | view.on('add', function (itemView) { 57 | itemView.$el.effect('slide', function () { 58 | widget._makeEditable(itemView); 59 | }); 60 | }); 61 | }, 62 | 63 | _makeEditable: function (itemView) { 64 | this.options.editableOptions.disabled = this.options.disabled; 65 | this.options.editableOptions.model = itemView.model; 66 | itemView.$el.midgardEditable(this.options.editableOptions); 67 | }, 68 | 69 | _init: function () { 70 | if (this.options.disabled) { 71 | this.disable(); 72 | return; 73 | } 74 | this.enable(); 75 | }, 76 | 77 | hideButtons: function () { 78 | _.each(this.addButtons, function (button) { 79 | button.hide(); 80 | }); 81 | }, 82 | 83 | showButtons: function () { 84 | _.each(this.addButtons, function (button) { 85 | button.show(); 86 | }); 87 | }, 88 | 89 | checkCollectionConstraints: function () { 90 | if (this.options.disabled) { 91 | return; 92 | } 93 | 94 | if (!this.options.view.canAdd()) { 95 | this.hideButtons(); 96 | return; 97 | } 98 | 99 | if (!this.options.definition) { 100 | // We have now information on the constraints applying to this collection 101 | this.showButtons(); 102 | return; 103 | } 104 | 105 | if (!this.options.definition.max || this.options.definition.max === -1) { 106 | // No maximum constraint 107 | this.showButtons(); 108 | return; 109 | } 110 | 111 | if (this.options.collection.length < this.options.definition.max) { 112 | this.showButtons(); 113 | return; 114 | } 115 | // Collection is already full by its definition 116 | this.hideButtons(); 117 | }, 118 | 119 | enable: function () { 120 | var widget = this; 121 | 122 | var addButton = jQuery(_.template(this.options.templates.button, { 123 | icon: 'plus', 124 | label: this.options.editableOptions.localize('Add', this.options.editableOptions.language) 125 | })).button(); 126 | addButton.addClass('midgard-create-add'); 127 | addButton.click(function () { 128 | widget.addItem(addButton); 129 | }); 130 | jQuery(widget.options.view.el).after(addButton); 131 | 132 | widget.addButtons.push(addButton); 133 | widget.checkCollectionConstraints(); 134 | }, 135 | 136 | disable: function () { 137 | _.each(this.addButtons, function (button) { 138 | button.remove(); 139 | }); 140 | this.addButtons = []; 141 | }, 142 | 143 | _getTypeActions: function (options) { 144 | var widget = this; 145 | var actions = []; 146 | _.each(this.options.definition.range, function (type) { 147 | var nsType = widget.options.collection.vie.namespaces.uri(type); 148 | if (!widget.options.view.canAdd(nsType)) { 149 | return; 150 | } 151 | actions.push({ 152 | name: type, 153 | label: type, 154 | cb: function () { 155 | widget.options.collection.add({ 156 | '@type': type 157 | }, options); 158 | }, 159 | className: 'create-ui-btn' 160 | }); 161 | }); 162 | return actions; 163 | }, 164 | 165 | addItem: function (button, options) { 166 | if (options === undefined) { 167 | options = {}; 168 | } 169 | var addOptions = _.extend({}, options, { validate: false }); 170 | 171 | var itemData = {}; 172 | if (this.options.definition && this.options.definition.range) { 173 | if (this.options.definition.range.length === 1) { 174 | // Items can be of single type, add that 175 | itemData['@type'] = this.options.definition.range[0]; 176 | } else { 177 | // Ask user which type to add 178 | jQuery('body').midgardNotifications('create', { 179 | bindTo: button, 180 | gravity: 'L', 181 | body: this.options.editableOptions.localize('Choose type to add', this.options.editableOptions.language), 182 | timeout: 0, 183 | actions: this._getTypeActions(addOptions) 184 | }); 185 | return; 186 | } 187 | } else { 188 | // Check the view templates for possible non-Thing type to use 189 | var keys = _.keys(this.options.view.templates); 190 | if (keys.length == 2) { 191 | itemData['@type'] = keys[0]; 192 | } 193 | } 194 | this.options.collection.add(itemData, addOptions); 195 | } 196 | }); 197 | })(jQuery); 198 | -------------------------------------------------------------------------------- /src/collectionWidgets/jquery.Midgard.midgardCreateCollectionAddBetween.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2011-2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false console:false */ 11 | 'use strict'; 12 | 13 | // # Widget for adding items anywhere inside a collection 14 | jQuery.widget('Midgard.midgardCollectionAddBetween', jQuery.Midgard.midgardCollectionAdd, { 15 | _bindCollectionView: function (view) { 16 | var widget = this; 17 | view.on('add', function (itemView) { 18 | //itemView.el.effect('slide'); 19 | widget._makeEditable(itemView); 20 | widget._refreshButtons(); 21 | }); 22 | view.on('remove', function () { 23 | widget._refreshButtons(); 24 | }); 25 | }, 26 | 27 | _refreshButtons: function () { 28 | var widget = this; 29 | window.setTimeout(function () { 30 | widget.disable(); 31 | widget.enable(); 32 | }, 1); 33 | }, 34 | 35 | prepareButton: function (index) { 36 | var widget = this; 37 | var addButton = jQuery(_.template(this.options.templates.button, { 38 | icon: 'plus', 39 | label: '' 40 | })).button(); 41 | addButton.addClass('midgard-create-add'); 42 | addButton.click(function () { 43 | widget.addItem(addButton, { 44 | at: index 45 | }); 46 | }); 47 | return addButton; 48 | }, 49 | 50 | enable: function () { 51 | var widget = this; 52 | 53 | var firstAddButton = widget.prepareButton(0); 54 | jQuery(widget.options.view.el).prepend(firstAddButton); 55 | widget.addButtons.push(firstAddButton); 56 | jQuery.each(widget.options.view.entityViews, function (cid, view) { 57 | var index = widget.options.collection.indexOf(view.model); 58 | var addButton = widget.prepareButton(index + 1); 59 | jQuery(view.el).append(addButton); 60 | widget.addButtons.push(addButton); 61 | }); 62 | 63 | this.checkCollectionConstraints(); 64 | }, 65 | 66 | disable: function () { 67 | var widget = this; 68 | jQuery.each(widget.addButtons, function (idx, button) { 69 | button.remove(); 70 | }); 71 | widget.addButtons = []; 72 | } 73 | }); 74 | })(jQuery); 75 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableBase.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Tobias Herrmann, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false document:false */ 11 | 'use strict'; 12 | 13 | // # Base property editor widget 14 | // 15 | // This property editor widget provides a very simplistic `contentEditable` 16 | // property editor that can be used as standalone, but should more usually be 17 | // used as the base class for other property editor widgets. 18 | // This property editor widget is only useful for textual properties! 19 | // 20 | // Subclassing this base property editor widget is easy: 21 | // 22 | // jQuery.widget('Namespace.MyWidget', jQuery.Create.editWidget, { 23 | // // override any properties 24 | // }); 25 | jQuery.widget('Midgard.editWidget', { 26 | options: { 27 | disabled: false, 28 | vie: null 29 | }, 30 | // override to enable the widget 31 | enable: function () { 32 | this.element.attr('contenteditable', 'true'); 33 | }, 34 | // override to disable the widget 35 | disable: function (disable) { 36 | this.element.attr('contenteditable', 'false'); 37 | }, 38 | // called by the jQuery UI plugin factory when creating the property editor 39 | // widget instance 40 | _create: function () { 41 | this._registerWidget(); 42 | this._initialize(); 43 | 44 | if (_.isFunction(this.options.decorate) && _.isFunction(this.options.decorateParams)) { 45 | // TRICKY: we can't use this.options.decorateParams()'s 'propertyName' 46 | // parameter just yet, because it will only be available after this 47 | // object has been created, but we're currently in the constructor! 48 | // Hence we have to duplicate part of its logic here. 49 | this.options.decorate(this.options.decorateParams(null, { 50 | propertyName: this.options.property, 51 | propertyEditor: this, 52 | propertyElement: this.element, 53 | // Deprecated. 54 | editor: this, 55 | predicate: this.options.property, 56 | element: this.element 57 | })); 58 | } 59 | }, 60 | // called every time the property editor widget is called 61 | _init: function () { 62 | if (this.options.disabled) { 63 | this.disable(); 64 | return; 65 | } 66 | this.enable(); 67 | }, 68 | // override this function to initialize the property editor widget functions 69 | _initialize: function () { 70 | var self = this; 71 | this.element.on('focus', function () { 72 | if (self.options.disabled) { 73 | return; 74 | } 75 | self.options.activated(); 76 | }); 77 | this.element.on('blur', function () { 78 | if (self.options.disabled) { 79 | return; 80 | } 81 | self.options.deactivated(); 82 | }); 83 | var before = this.element.text(); 84 | this.element.on('keyup paste', function (event) { 85 | if (self.options.disabled) { 86 | return; 87 | } 88 | var current = jQuery(this).text(); 89 | if (before !== current) { 90 | before = current; 91 | self.options.changed(current); 92 | } 93 | }); 94 | }, 95 | // used to register the property editor widget name with the DOM element 96 | _registerWidget: function () { 97 | this.element.data("createWidgetName", this.widgetName); 98 | } 99 | }); 100 | })(jQuery); 101 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorAloha.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Tobias Herrmann, IKS Consortium 4 | // (c) 2011 Rene Kapusta, Evo42 5 | // Create may be freely distributed under the MIT license. 6 | // For all details and documentation: 7 | // http://createjs.org/ 8 | */ 9 | (function (jQuery, undefined) { 10 | // Run JavaScript in strict mode 11 | /*global jQuery:false _:false document:false Aloha:false */ 12 | 'use strict'; 13 | 14 | // # Aloha editing widget 15 | // 16 | // This widget allows editing textual contents using the 17 | // [Aloha](http://aloha-editor.org) rich text editor. 18 | // 19 | // Due to licensing incompatibilities, Aloha Editor needs to be installed 20 | // and configured separately. 21 | jQuery.widget('Midgard.alohaWidget', jQuery.Midgard.editWidget, { 22 | _initialize: function () {}, 23 | enable: function () { 24 | var options = this.options; 25 | var editable; 26 | var currentElement = Aloha.jQuery(options.element.get(0)).aloha(); 27 | _.each(Aloha.editables, function (aloha) { 28 | // Find the actual editable instance so we can hook to the events 29 | // correctly 30 | if (aloha.obj.get(0) === currentElement.get(0)) { 31 | editable = aloha; 32 | } 33 | }); 34 | if (!editable) { 35 | return; 36 | } 37 | editable.vieEntity = options.entity; 38 | 39 | var checkEditableChanged; 40 | 41 | function activeEditableChanged() { 42 | if (Aloha.activeEditable.isModified()) { 43 | options.changed(Aloha.activeEditable.getContents()); 44 | Aloha.activeEditable.setUnmodified(); 45 | } 46 | } 47 | 48 | // Subscribe to activation and deactivation events 49 | Aloha.bind('aloha-editable-activated', function (event, data) { 50 | if (data.editable !== editable) { 51 | return; 52 | } 53 | checkEditableChanged = window.setInterval(activeEditableChanged, 500); 54 | options.activated(); 55 | }); 56 | Aloha.bind('aloha-editable-deactivated', function (event, data) { 57 | if (data.editable !== editable) { 58 | return; 59 | } 60 | window.clearInterval(checkEditableChanged); 61 | options.deactivated(); 62 | }); 63 | 64 | Aloha.bind('aloha-smart-content-changed', function (event, data) { 65 | if (data.editable !== editable) { 66 | return; 67 | } 68 | if (!data.editable.isModified()) { 69 | return true; 70 | } 71 | options.changed(data.editable.getContents()); 72 | data.editable.setUnmodified(); 73 | }); 74 | this.options.disabled = false; 75 | }, 76 | disable: function () { 77 | Aloha.jQuery(this.options.element.get(0)).mahalo(); 78 | this.options.disabled = true; 79 | } 80 | }); 81 | })(jQuery); 82 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorCKEditor.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Tobias Herrmann, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | */ 7 | (function (jQuery, undefined) { 8 | // Run JavaScript in strict mode 9 | /*global jQuery:false _:false document:false CKEDITOR:false */ 10 | 'use strict'; 11 | 12 | // # CKEditor editing widget 13 | // 14 | // This widget allows editing textual content areas with the 15 | // [CKEditor](http://ckeditor.com/) rich text editor. 16 | jQuery.widget('Midgard.ckeditorWidget', jQuery.Midgard.editWidget, { 17 | options: { 18 | editorOptions: {}, 19 | disabled: true, 20 | vie: null 21 | }, 22 | enable: function () { 23 | this.element.attr('contentEditable', 'true'); 24 | this.editor = CKEDITOR.inline(this.element.get(0)); 25 | this.options.disabled = false; 26 | 27 | var widget = this; 28 | this.editor.on('focus', function () { 29 | widget.options.activated(); 30 | }); 31 | this.editor.on('blur', function () { 32 | widget.options.deactivated(); 33 | widget.options.changed(widget.editor.getData()); 34 | }); 35 | this.editor.on('change', function () { 36 | widget.options.changed(widget.editor.getData()); 37 | }); 38 | this.editor.on('configLoaded', function() { 39 | if (widget.options.editorOptions !== undefined) { 40 | jQuery.each(widget.options.editorOptions, function(optionName, option) { 41 | widget.editor.config[optionName] = option; 42 | }); 43 | } 44 | }); 45 | }, 46 | 47 | disable: function () { 48 | if (!this.editor) { 49 | return; 50 | } 51 | this.element.attr('contentEditable', 'false'); 52 | this.editor.destroy(); 53 | this.editor = null; 54 | }, 55 | 56 | _initialize: function () { 57 | CKEDITOR.disableAutoInline = true; 58 | } 59 | }); 60 | })(jQuery); 61 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorHallo.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Tobias Herrmann, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false document:false */ 11 | 'use strict'; 12 | 13 | // # Hallo editing widget 14 | // 15 | // This widget allows editing textual content areas with the 16 | // [Hallo](http://hallojs.org) rich text editor. 17 | jQuery.widget('Midgard.halloWidget', jQuery.Midgard.editWidget, { 18 | options: { 19 | editorOptions: {}, 20 | disabled: true, 21 | toolbarState: 'full', 22 | vie: null, 23 | entity: null 24 | }, 25 | enable: function () { 26 | jQuery(this.element).hallo({ 27 | editable: true 28 | }); 29 | this.options.disabled = false; 30 | }, 31 | 32 | disable: function () { 33 | jQuery(this.element).hallo({ 34 | editable: false 35 | }); 36 | this.options.disabled = true; 37 | }, 38 | 39 | _initialize: function () { 40 | jQuery(this.element).hallo(this.getHalloOptions()); 41 | var self = this; 42 | jQuery(this.element).on('halloactivated', function (event, data) { 43 | self.options.activated(); 44 | }); 45 | jQuery(this.element).on('hallodeactivated', function (event, data) { 46 | self.options.deactivated(); 47 | }); 48 | jQuery(this.element).on('hallomodified', function (event, data) { 49 | self.options.changed(data.content); 50 | data.editable.setUnmodified(); 51 | }); 52 | 53 | jQuery(document).on('midgardtoolbarstatechange', function(event, data) { 54 | // Switch between Hallo configurations when toolbar state changes 55 | if (data.display === self.options.toolbarState) { 56 | return; 57 | } 58 | self.options.toolbarState = data.display; 59 | if (!self.element.data('IKS-hallo') && !self.element.data('hallo')) { 60 | // Hallo not yet instantiated 61 | return; 62 | } 63 | var newOptions = self.getHalloOptions(); 64 | self.element.hallo('changeToolbar', newOptions.parentElement, newOptions.toolbar, true); 65 | }); 66 | }, 67 | 68 | getHalloOptions: function() { 69 | var defaults = { 70 | plugins: { 71 | halloformat: {}, 72 | halloblock: {}, 73 | hallolists: {}, 74 | hallolink: {}, 75 | halloimage: { 76 | entity: this.options.entity 77 | } 78 | }, 79 | buttonCssClass: 'create-ui-btn-small', 80 | placeholder: '[' + this.options.property + ']' 81 | }; 82 | 83 | if (typeof this.element.annotate === 'function' && this.options.vie.services.stanbol) { 84 | // Enable Hallo Annotate plugin by default if user has annotate.js 85 | // loaded and VIE has Stanbol enabled 86 | defaults.plugins.halloannotate = { 87 | vie: this.options.vie 88 | }; 89 | } 90 | 91 | if (this.options.toolbarState === 'full') { 92 | // Use fixed toolbar in the Create tools area 93 | defaults.parentElement = jQuery('.create-ui-toolbar-dynamictoolarea .create-ui-tool-freearea'); 94 | defaults.toolbar = 'halloToolbarFixed'; 95 | } else { 96 | // Tools area minimized, use floating toolbar 97 | defaults.parentElement = 'body'; 98 | defaults.toolbar = 'halloToolbarContextual'; 99 | } 100 | return _.extend(defaults, this.options.editorOptions); 101 | } 102 | }); 103 | })(jQuery); 104 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorMedium.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false document:false */ 11 | 'use strict'; 12 | 13 | // # Medium Editor editing widget 14 | // 15 | // This widget allows editing textual content areas with the 16 | // [Medium Editor](https://github.com/daviferreira/medium-editor) rich text editor. 17 | jQuery.widget('Midgard.mediumWidget', jQuery.Midgard.editWidget, { 18 | editor: null, 19 | listener: null, 20 | 21 | options: { 22 | editorOptions: {}, 23 | disabled: true 24 | }, 25 | 26 | enable: function () { 27 | this.editor = new MediumEditor(this._buildSelector(), this.editorOptions); 28 | this.listener = function () { 29 | this.options.changed(jQuery(this.element).text()); 30 | }.bind(this); 31 | 32 | jQuery(this.element).on('keyup', this.listener); 33 | // TODO: Change events, see https://github.com/daviferreira/medium-editor/issues/17 34 | }, 35 | 36 | disable: function () { 37 | jQuery(this.element).off('keyup', this.listener); 38 | // TODO: Close the editor, see https://github.com/daviferreira/medium-editor/issues/19 39 | }, 40 | 41 | _buildSelector: function () { 42 | var aboutSelector = '[about="' + this.options.entity.getSubjectUri() + '"]'; 43 | var propertySelector = '[property="' + this.options.property + '"]'; 44 | return aboutSelector + ' ' + propertySelector; 45 | } 46 | }); 47 | })(jQuery); 48 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorRedactor.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false document:false */ 11 | 'use strict'; 12 | 13 | // # Redactor editing widget 14 | // 15 | // This widget allows editing textual content areas with the 16 | // [Redactor](http://redactorjs.com/) rich text editor. 17 | jQuery.widget('Midgard.redactorWidget', jQuery.Midgard.editWidget, { 18 | editor: null, 19 | 20 | options: { 21 | editorOptions: {}, 22 | disabled: true 23 | }, 24 | 25 | enable: function () { 26 | jQuery(this.element).redactor(this.getRedactorOptions()); 27 | this.options.disabled = false; 28 | }, 29 | 30 | disable: function () { 31 | jQuery(this.element).destroyEditor(); 32 | this.options.disabled = true; 33 | }, 34 | 35 | _initialize: function () { 36 | var self = this; 37 | jQuery(this.element).on('focus', function (event) { 38 | self.options.activated(); 39 | }); 40 | /* 41 | jQuery(this.element).on('blur', function (event) { 42 | self.options.deactivated(); 43 | }); 44 | */ 45 | }, 46 | 47 | getRedactorOptions: function () { 48 | var self = this; 49 | var overrides = { 50 | keyupCallback: function (obj, event) { 51 | self.options.changed(jQuery(self.element).getCode()); 52 | }, 53 | execCommandCallback: function (obj, command) { 54 | self.options.changed(jQuery(self.element).getCode()); 55 | } 56 | }; 57 | 58 | return _.extend(self.options.editorOptions, overrides); 59 | } 60 | }); 61 | })(jQuery); 62 | -------------------------------------------------------------------------------- /src/editingWidgets/jquery.Midgard.midgardEditableEditorTinyMCE.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Tobias Herrmann, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | */ 7 | (function (jQuery, undefined) { 8 | // Run JavaScript in strict mode 9 | /*global jQuery:false _:false document:false tinymce:false */ 10 | 'use strict'; 11 | 12 | // # TinyMCE editing widget 13 | // 14 | // This widget allows editing textual content areas with the 15 | // [TinyMCE](http://www.tinymce.com/) rich text editor. 16 | jQuery.widget('Midgard.tinymceWidget', jQuery.Midgard.editWidget, { 17 | enable: function () { 18 | this.element.attr('contentEditable', 'true'); 19 | var id = this.element.attr('id'); 20 | 21 | if (!id || tinymce.get(id)) { 22 | id = tinymce.DOM.uniqueId(); 23 | } 24 | 25 | this.element.attr('id', id); 26 | this.editor = new tinymce.Editor(id, {inline: true}, tinymce.EditorManager); 27 | this.editor.render(true); 28 | this.options.disabled = false; 29 | 30 | var widget = this; 31 | this.editor.on('focus', function () { 32 | widget.options.activated(); 33 | }); 34 | this.editor.on('blur', function () { 35 | widget.options.deactivated(); 36 | widget.options.changed(widget.editor.getContent()); 37 | }); 38 | this.editor.on('change', function () { 39 | widget.options.changed(widget.editor.getContent()); 40 | }); 41 | }, 42 | 43 | disable: function () { 44 | if (!this.editor) { 45 | return; 46 | } 47 | this.element.attr('contentEditable', 'false'); 48 | this.editor.remove(); 49 | this.editor = null; 50 | } 51 | }); 52 | })(jQuery); 53 | -------------------------------------------------------------------------------- /src/jquery.Midgard.midgardMetadata.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false */ 11 | 'use strict'; 12 | 13 | jQuery.widget('Midgard.midgardMetadata', { 14 | contentArea: null, 15 | editorElements: {}, 16 | options: { 17 | vie: null, 18 | templates: { 19 | button: '', 20 | contentArea: '' 21 | }, 22 | localize: function (id, language) { 23 | return window.midgardCreate.localize(id, language); 24 | }, 25 | language: null, 26 | createElement: 'body', 27 | editableNs: 'midgardeditable' 28 | }, 29 | 30 | _create: function () { 31 | this._render(); 32 | }, 33 | 34 | _init: function () { 35 | this._prepareEditors(); 36 | this._bindEditables(); 37 | }, 38 | 39 | _prepareEditors: function () { 40 | _.each(this.options.editors, function (configuration, editor) { 41 | // We need to create containers for each editor and instantiate them 42 | var editorArea = jQuery('
').addClass(editor); 43 | this.contentArea.append(editorArea); 44 | if (!_.isFunction(editorArea[editor])) { 45 | throw new Error('Metadata editor widget ' + editor + ' is not available'); 46 | } 47 | 48 | _.extend(configuration, { 49 | vie: this.options.vie, 50 | language: this.options.language, 51 | localize: this.options.localize, 52 | createElement: this.options.createElement, 53 | editableNs: this.options.editableNs 54 | }); 55 | 56 | editorArea[editor](configuration); 57 | this.editorElements[editor] = editorArea; 58 | }, this); 59 | }, 60 | 61 | activateEditors: function (data) { 62 | this.element.show(); 63 | _.each(this.options.editors, function (configuration, editor) { 64 | if (!this.editorElements[editor]) { 65 | return; 66 | } 67 | // An editable has been activated, pass the info on to the 68 | // editor widgets 69 | this.editorElements[editor][editor]('activate', data); 70 | }, this); 71 | }, 72 | 73 | _bindEditables: function () { 74 | var widget = this; 75 | var createElement = jQuery(this.options.createElement); 76 | createElement.on(this.options.editableNs + 'activated', function (event, data) { 77 | // An editable has been activated. Tell our metadata editors 78 | // about it 79 | widget.activateEditors({ 80 | entity: data.entity, 81 | entityElement: data.entityElement, 82 | predicate: data.predicate 83 | }); 84 | }); 85 | }, 86 | 87 | _prepareEditorArea: function (button) { 88 | var contentArea = jQuery(_.template(this.options.templates.contentArea, {})); 89 | contentArea.hide(); 90 | return contentArea; 91 | }, 92 | 93 | _render: function () { 94 | var widget = this; 95 | 96 | var button = jQuery(_.template(this.options.templates.button, { 97 | icon: 'info-sign', 98 | label: this.options.localize('Metadata', this.options.language) 99 | })); 100 | 101 | this.element.empty(); 102 | this.element.append(button); 103 | this.element.hide(); 104 | 105 | this.contentArea = this._prepareEditorArea(button); 106 | button.after(this.contentArea); 107 | 108 | button.on('click', function(event) { 109 | event.preventDefault(); 110 | 111 | var offset = button.position(); 112 | widget.contentArea.css({ 113 | position: 'absolute', 114 | left: offset.left 115 | }); 116 | 117 | widget.contentArea.toggle(); 118 | }); 119 | } 120 | }); 121 | })(jQuery); 122 | -------------------------------------------------------------------------------- /src/jquery.Midgard.midgardStorage.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2011-2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false */ 11 | 'use strict'; 12 | 13 | jQuery.widget('Midgard.midgardStorage', { 14 | saveEnabled: true, 15 | options: { 16 | // Whether to use localstorage 17 | localStorage: false, 18 | // String prefix for localStorage identifiers 19 | storagePrefix: '', 20 | removeLocalstorageOnIgnore: true, 21 | // VIE instance to use for storage handling 22 | vie: null, 23 | // URL callback for Backbone.sync 24 | url: '', 25 | // Whether to enable automatic saving 26 | autoSave: false, 27 | // How often to autosave in milliseconds 28 | autoSaveInterval: 5000, 29 | // Whether to save entities that are referenced by entities 30 | // we're saving to the server. 31 | saveReferencedNew: false, 32 | saveReferencedChanged: false, 33 | // Namespace used for events from midgardEditable-derived widget 34 | editableNs: 'midgardeditable', 35 | // CSS selector for the Edit button, leave to null to not bind 36 | // notifications to any element 37 | editSelector: '#midgardcreate-edit a', 38 | localize: function (id, language) { 39 | return window.midgardCreate.localize(id, language); 40 | }, 41 | language: null 42 | }, 43 | 44 | _create: function () { 45 | var widget = this; 46 | this.changedModels = []; 47 | 48 | if (window.localStorage) { 49 | this.options.localStorage = true; 50 | } 51 | 52 | this.vie = this.options.vie; 53 | 54 | this.vie.entities.on('add', function (model) { 55 | // Add the back-end URL used by Backbone.sync 56 | model.url = widget.options.url; 57 | model.toJSON = model.toJSONLD; 58 | }); 59 | 60 | widget._bindEditables(); 61 | if (widget.options.autoSave) { 62 | widget._autoSave(); 63 | } 64 | }, 65 | 66 | _autoSave: function () { 67 | var widget = this; 68 | widget.saveEnabled = true; 69 | 70 | var doAutoSave = function () { 71 | if (!widget.saveEnabled) { 72 | return; 73 | } 74 | 75 | if (widget.changedModels.length === 0) { 76 | return; 77 | } 78 | 79 | widget.saveRemoteAll({ 80 | // We make autosaves silent so that potential changes from server 81 | // don't disrupt user while writing. 82 | silent: true 83 | }); 84 | }; 85 | 86 | var timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval); 87 | 88 | this.element.on('startPreventSave', function () { 89 | if (timeout) { 90 | window.clearInterval(timeout); 91 | timeout = null; 92 | } 93 | widget.disableAutoSave(); 94 | }); 95 | this.element.on('stopPreventSave', function () { 96 | if (!timeout) { 97 | timeout = window.setInterval(doAutoSave, widget.options.autoSaveInterval); 98 | } 99 | widget.enableAutoSave(); 100 | }); 101 | 102 | }, 103 | 104 | enableAutoSave: function () { 105 | this.saveEnabled = true; 106 | }, 107 | 108 | disableAutoSave: function () { 109 | this.saveEnabled = false; 110 | }, 111 | 112 | _bindEditables: function () { 113 | var widget = this; 114 | this.restorables = []; 115 | var restorer; 116 | 117 | widget.element.on(widget.options.editableNs + 'changed', function (event, options) { 118 | if (_.indexOf(widget.changedModels, options.instance) === -1) { 119 | widget.changedModels.push(options.instance); 120 | options.instance.midgardStorageVersion = 1; 121 | } else { 122 | options.instance.midgardStorageVersion++; 123 | } 124 | widget._saveLocal(options.instance); 125 | }); 126 | 127 | widget.element.on(widget.options.editableNs + 'disable', function (event, options) { 128 | widget.revertChanges(options.instance); 129 | }); 130 | 131 | widget.element.on(widget.options.editableNs + 'enable', function (event, options) { 132 | if (!options.instance._originalAttributes) { 133 | options.instance._originalAttributes = _.clone(options.instance.attributes); 134 | } 135 | 136 | if (!options.instance.isNew() && widget._checkLocal(options.instance)) { 137 | // We have locally-stored modifications, user needs to be asked 138 | widget.restorables.push(options.instance); 139 | } 140 | 141 | /*_.each(options.instance.attributes, function (attributeValue, property) { 142 | if (attributeValue instanceof widget.vie.Collection) { 143 | widget._readLocalReferences(options.instance, property, attributeValue); 144 | } 145 | });*/ 146 | }); 147 | 148 | widget.element.on('midgardcreatestatechange', function (event, options) { 149 | if (options.state === 'browse' || widget.restorables.length === 0) { 150 | widget.restorables = []; 151 | if (restorer) { 152 | restorer.close(); 153 | } 154 | return; 155 | } 156 | restorer = widget.checkRestore(); 157 | }); 158 | 159 | widget.element.on('midgardstorageloaded', function (event, options) { 160 | if (_.indexOf(widget.changedModels, options.instance) === -1) { 161 | widget.changedModels.push(options.instance); 162 | } 163 | }); 164 | }, 165 | 166 | checkRestore: function () { 167 | var widget = this; 168 | if (widget.restorables.length === 0) { 169 | return; 170 | } 171 | 172 | var message; 173 | var restorer; 174 | if (widget.restorables.length === 1) { 175 | message = _.template(widget.options.localize('localModification', widget.options.language), { 176 | label: widget.restorables[0].getSubjectUri() 177 | }); 178 | } else { 179 | message = _.template(widget.options.localize('localModifications', widget.options.language), { 180 | number: widget.restorables.length 181 | }); 182 | } 183 | 184 | var doRestore = function (event, notification) { 185 | widget.restoreLocalAll(); 186 | restorer.close(); 187 | }; 188 | 189 | var doIgnore = function (event, notification) { 190 | widget.ignoreLocal(); 191 | restorer.close(); 192 | }; 193 | 194 | restorer = jQuery('body').midgardNotifications('create', { 195 | bindTo: widget.options.editSelector, 196 | gravity: 'TR', 197 | body: message, 198 | timeout: 0, 199 | actions: [ 200 | { 201 | name: 'restore', 202 | label: widget.options.localize('Restore', widget.options.language), 203 | cb: doRestore, 204 | className: 'create-ui-btn' 205 | }, 206 | { 207 | name: 'ignore', 208 | label: widget.options.localize('Ignore', widget.options.language), 209 | cb: doIgnore, 210 | className: 'create-ui-btn' 211 | } 212 | ], 213 | callbacks: { 214 | beforeShow: function () { 215 | if (!window.Mousetrap) { 216 | return; 217 | } 218 | window.Mousetrap.bind(['command+shift+r', 'ctrl+shift+r'], function (event) { 219 | event.preventDefault(); 220 | doRestore(); 221 | }); 222 | window.Mousetrap.bind(['command+shift+i', 'ctrl+shift+i'], function (event) { 223 | event.preventDefault(); 224 | doIgnore(); 225 | }); 226 | }, 227 | afterClose: function () { 228 | if (!window.Mousetrap) { 229 | return; 230 | } 231 | window.Mousetrap.unbind(['command+shift+r', 'ctrl+shift+r']); 232 | window.Mousetrap.unbind(['command+shift+i', 'ctrl+shift+i']); 233 | } 234 | } 235 | }); 236 | return restorer; 237 | }, 238 | 239 | restoreLocalAll: function () { 240 | _.each(this.restorables, function (instance) { 241 | this.readLocal(instance); 242 | }, this); 243 | this.restorables = []; 244 | }, 245 | 246 | ignoreLocal: function () { 247 | if (this.options.removeLocalstorageOnIgnore) { 248 | _.each(this.restorables, function (instance) { 249 | this._removeLocal(instance); 250 | }, this); 251 | } 252 | this.restorables = []; 253 | }, 254 | 255 | saveReferences: function (model) { 256 | _.each(model.attributes, function (value, property) { 257 | if (!value || !value.isCollection) { 258 | return; 259 | } 260 | 261 | value.each(function (referencedModel) { 262 | if (this.changedModels.indexOf(referencedModel) !== -1) { 263 | // The referenced model is already in the save queue 264 | return; 265 | } 266 | 267 | if (referencedModel.isNew() && this.options.saveReferencedNew) { 268 | return referencedModel.save(); 269 | } 270 | 271 | if (referencedModel.hasChanged() && this.options.saveReferencedChanged) { 272 | return referencedModel.save(); 273 | } 274 | }, this); 275 | }, this); 276 | }, 277 | 278 | saveRemote: function (model, options) { 279 | // Optionally handle entities referenced in this model first 280 | this.saveReferences(model); 281 | 282 | this._trigger('saveentity', null, { 283 | entity: model, 284 | options: options 285 | }); 286 | 287 | var widget = this, 288 | previousVersion = model.midgardStorageVersion; 289 | model.save(null, _.extend({}, options, { 290 | success: function (m, response) { 291 | // From now on we're going with the values we have on server 292 | model._originalAttributes = _.clone(model.attributes); 293 | widget._removeLocal(model); 294 | window.setTimeout(function () { 295 | // Remove the model from the list of changed models after saving if no other change was made to the model 296 | if (model.midgardStorageVersion == previousVersion) { 297 | widget.changedModels.splice(widget.changedModels.indexOf(model), 1); 298 | } 299 | }, 0); 300 | if (_.isFunction(options.success)) { 301 | options.success(m, response); 302 | } 303 | widget._trigger('savedentity', null, { 304 | entity: model, 305 | options: options 306 | }); 307 | }, 308 | error: function (m, response) { 309 | if (_.isFunction(options.error)) { 310 | options.error(m, response); 311 | } 312 | } 313 | })); 314 | }, 315 | 316 | saveRemoteAll: function (options) { 317 | var widget = this; 318 | if (widget.changedModels.length === 0) { 319 | return; 320 | } 321 | 322 | widget._trigger('save', null, { 323 | entities: widget.changedModels, 324 | options: options, 325 | // Deprecated 326 | models: widget.changedModels 327 | }); 328 | 329 | var notification_msg; 330 | var needed = widget.changedModels.length; 331 | if (needed > 1) { 332 | notification_msg = _.template(widget.options.localize('saveSuccessMultiple', widget.options.language), { 333 | number: needed 334 | }); 335 | } else { 336 | notification_msg = _.template(widget.options.localize('saveSuccess', widget.options.language), { 337 | label: widget.changedModels[0].getSubjectUri() 338 | }); 339 | } 340 | 341 | widget.disableAutoSave(); 342 | _.each(widget.changedModels, function (model) { 343 | this.saveRemote(model, { 344 | success: function (m, response) { 345 | needed--; 346 | if (needed <= 0) { 347 | // All models were happily saved 348 | widget._trigger('saved', null, { 349 | options: options 350 | }); 351 | if (options && _.isFunction(options.success)) { 352 | options.success(m, response); 353 | } 354 | jQuery('body').midgardNotifications('create', { 355 | body: notification_msg 356 | }); 357 | widget.enableAutoSave(); 358 | } 359 | }, 360 | error: function (m, err) { 361 | if (options && _.isFunction(options.error)) { 362 | options.error(m, err); 363 | } 364 | jQuery('body').midgardNotifications('create', { 365 | body: _.template(widget.options.localize('saveError', widget.options.language), { 366 | error: err.responseText || '' 367 | }), 368 | timeout: 0 369 | }); 370 | 371 | widget._trigger('error', null, { 372 | instance: model 373 | }); 374 | } 375 | }); 376 | }, this); 377 | }, 378 | 379 | _saveLocal: function (model) { 380 | if (!this.options.localStorage) { 381 | return; 382 | } 383 | 384 | if (model.isNew()) { 385 | // Anonymous object, save as refs instead 386 | if (!model.primaryCollection) { 387 | return; 388 | } 389 | return this._saveLocalReferences(model.primaryCollection.subject, model.primaryCollection.predicate, model); 390 | } 391 | var key = this.options.storagePrefix + model.getSubjectUri(); 392 | window.localStorage.setItem(key, JSON.stringify(model.toJSONLD())); 393 | }, 394 | 395 | _getReferenceId: function (model, property) { 396 | return model.id + ':' + property; 397 | }, 398 | 399 | _saveLocalReferences: function (subject, predicate, model) { 400 | if (!this.options.localStorage) { 401 | return; 402 | } 403 | 404 | if (!subject || !predicate) { 405 | return; 406 | } 407 | 408 | var widget = this; 409 | var identifier = this.options.storagePrefix + subject + ':' + predicate; 410 | var json = model.toJSONLD(); 411 | if (window.localStorage.getItem(identifier)) { 412 | var referenceList = JSON.parse(window.localStorage.getItem(identifier)); 413 | var index = _.pluck(referenceList, '@').indexOf(json['@']); 414 | if (index !== -1) { 415 | referenceList[index] = json; 416 | } else { 417 | referenceList.push(json); 418 | } 419 | window.localStorage.setItem(identifier, JSON.stringify(referenceList)); 420 | return; 421 | } 422 | window.localStorage.setItem(identifier, JSON.stringify([json])); 423 | }, 424 | 425 | _checkLocal: function (model) { 426 | if (!this.options.localStorage) { 427 | return false; 428 | } 429 | 430 | var key = this.options.storagePrefix + model.getSubjectUri(); 431 | var local = window.localStorage.getItem(key); 432 | if (!local) { 433 | return false; 434 | } 435 | 436 | return true; 437 | }, 438 | 439 | hasLocal: function (model) { 440 | if (!this.options.localStorage) { 441 | return false; 442 | } 443 | var key = this.options.storagePrefix + model.getSubjectUri(); 444 | if (!window.localStorage.getItem(key)) { 445 | return false; 446 | } 447 | return true; 448 | }, 449 | 450 | readLocal: function (model) { 451 | if (!this.options.localStorage) { 452 | return; 453 | } 454 | 455 | var key = this.options.storagePrefix + model.getSubjectUri(); 456 | var local = window.localStorage.getItem(key); 457 | if (!local) { 458 | return; 459 | } 460 | if (!model._originalAttributes) { 461 | model._originalAttributes = _.clone(model.attributes); 462 | } 463 | var parsed = JSON.parse(local); 464 | var entity = this.vie.entities.addOrUpdate(parsed, { 465 | overrideAttributes: true 466 | }); 467 | 468 | this._trigger('loaded', null, { 469 | instance: entity 470 | }); 471 | }, 472 | 473 | _readLocalReferences: function (model, property, collection) { 474 | if (!this.options.localStorage) { 475 | return; 476 | } 477 | 478 | var identifier = this.options.storagePrefix + this._getReferenceId(model, property); 479 | var local = window.localStorage.getItem(identifier); 480 | if (!local) { 481 | return; 482 | } 483 | collection.add(JSON.parse(local)); 484 | }, 485 | 486 | revertChanges: function (model) { 487 | var widget = this; 488 | 489 | // Remove unsaved collection members 490 | if (!model) { return; } 491 | _.each(model.attributes, function (attributeValue, property) { 492 | if (attributeValue instanceof widget.vie.Collection) { 493 | var removables = []; 494 | attributeValue.forEach(function (model) { 495 | if (model.isNew()) { 496 | removables.push(model); 497 | } 498 | }); 499 | attributeValue.remove(removables); 500 | } 501 | }); 502 | 503 | // Restore original object properties 504 | if (!model.changedAttributes()) { 505 | if (model._originalAttributes) { 506 | model.set(model._originalAttributes); 507 | } 508 | return; 509 | } 510 | 511 | model.set(model.previousAttributes()); 512 | }, 513 | 514 | _removeLocal: function (model) { 515 | if (!this.options.localStorage) { 516 | return; 517 | } 518 | var key = this.options.storagePrefix + model.getSubjectUri(); 519 | window.localStorage.removeItem(key); 520 | } 521 | }); 522 | })(jQuery); 523 | -------------------------------------------------------------------------------- /src/jquery.Midgard.midgardToolbar.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2011-2012 Henri Bergius, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false */ 11 | 'use strict'; 12 | 13 | jQuery.widget('Midgard.midgardToolbar', { 14 | options: { 15 | display: 'full', 16 | templates: { 17 | minimized: '', 18 | full: '
<%= dynamic %><%= status %>
', 19 | toolcontainer: '
', 20 | toolarea: '
  • ' 21 | } 22 | }, 23 | 24 | _create: function () { 25 | this.element.append(this._getMinimized()); 26 | this.element.append(this._getFull()); 27 | 28 | var widget = this; 29 | jQuery('.create-ui-toggle', this.element).click(function () { 30 | if (widget.options.display === 'full') { 31 | widget.setDisplay('minimized'); 32 | } else { 33 | widget.setDisplay('full'); 34 | } 35 | }); 36 | 37 | jQuery(this.element).on('midgardcreatestatechange', function (event, options) { 38 | if (options.state == 'browse') { 39 | widget._clearWorkflows(); 40 | } 41 | }); 42 | 43 | jQuery(this.element).on('midgardworkflowschanged', function (event, options) { 44 | widget._clearWorkflows(); 45 | if (options.workflows.length) { 46 | options.workflows.each(function (workflow) { 47 | var workflowsInstance = jQuery('body').data('Midgard-midgardWorkflows'); 48 | if (!workflowsInstance) { 49 | // pre-1.10 jQuery UI 50 | workflowsInstance = jQuery('body').data('midgardWorkflows'); 51 | } 52 | var html = workflowsInstance.prepareItem(options.instance, workflow, function (err, model) { 53 | widget._clearWorkflows(); 54 | if (err) { 55 | return; 56 | } 57 | }); 58 | jQuery('.create-ui-tool-workflowarea', widget.element).append(html); 59 | }); 60 | } 61 | }); 62 | }, 63 | 64 | _init: function () { 65 | this.setDisplay(this.options.display); 66 | }, 67 | 68 | setDisplay: function (value) { 69 | if (value === this.options.display) { 70 | return; 71 | } 72 | if (value === 'minimized') { 73 | this.hide(); 74 | this.options.display = 'minimized'; 75 | } else { 76 | this.show(); 77 | this.options.display = 'full'; 78 | } 79 | this._trigger('statechange', null, this.options); 80 | }, 81 | 82 | hide: function () { 83 | jQuery('div.create-ui-toolbar-wrapper').fadeToggle('fast', 'linear'); 84 | }, 85 | 86 | show: function () { 87 | jQuery('div.create-ui-toolbar-wrapper').fadeToggle('fast', 'linear'); 88 | }, 89 | 90 | _getMinimized: function () { 91 | return jQuery(_.template(this.options.templates.minimized, {})); 92 | }, 93 | 94 | _getFull: function () { 95 | return jQuery(_.template(this.options.templates.full, { 96 | dynamic: _.template(this.options.templates.toolcontainer, { 97 | name: 'dynamic', 98 | content: 99 | _.template(this.options.templates.toolarea, { 100 | name: 'metadata' 101 | }) + 102 | _.template(this.options.templates.toolarea, { 103 | name: 'workflow' 104 | }) + 105 | _.template(this.options.templates.toolarea, { 106 | name: 'free' 107 | }) 108 | }), 109 | status: _.template(this.options.templates.toolcontainer, { 110 | name: 'status', 111 | content: '' 112 | }) 113 | })); 114 | }, 115 | 116 | _clearWorkflows: function () { 117 | jQuery('.create-ui-tool-workflowarea', this.element).empty(); 118 | } 119 | }); 120 | })(jQuery); 121 | -------------------------------------------------------------------------------- /src/jquery.Midgard.midgardWorkflows.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Jerry Jalava, IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false Backbone:false */ 11 | 'use strict'; 12 | 13 | jQuery.widget('Midgard.midgardWorkflows', { 14 | options: { 15 | url: function (model) {}, 16 | templates: { 17 | button: '' 18 | }, 19 | renderers: { 20 | button: function (model, workflow, action_cb, final_cb) { 21 | var button_id = 'midgardcreate-workflow_' + workflow.get('name'); 22 | var html = jQuery(_.template(this.options.templates.button, { 23 | id: button_id, 24 | label: workflow.get('label') 25 | })).button(); 26 | 27 | html.on('click', function (evt) { 28 | action_cb(model, workflow, final_cb); 29 | }); 30 | return html; 31 | } 32 | }, 33 | action_types: { 34 | backbone_save: function (model, workflow, callback) { 35 | var copy_of_url = model.url; 36 | var original_model = model.clone(); 37 | original_model.url = copy_of_url; 38 | 39 | var action = workflow.get('action'); 40 | if (action.url) { 41 | model.url = action.url; 42 | } 43 | original_model.save(null, { 44 | success: function (m) { 45 | model.url = copy_of_url; 46 | model.change(); 47 | callback(null, model); 48 | }, 49 | error: function (m, err) { 50 | model.url = copy_of_url; 51 | model.change(); 52 | callback(err, model); 53 | } 54 | }); 55 | }, 56 | backbone_destroy: function (model, workflow, callback) { 57 | var copy_of_url = model.url; 58 | var original_model = model.clone(); 59 | original_model.url = copy_of_url; 60 | 61 | var action = workflow.get('action'); 62 | if (action.url) { 63 | model.url = action.url; 64 | } 65 | 66 | model.destroy({ 67 | success: function (m) { 68 | model.url = copy_of_url; 69 | model.change(); 70 | callback(null, m); 71 | }, 72 | error: function (m, err) { 73 | model.url = copy_of_url; 74 | model.change(); 75 | callback(err, model); 76 | } 77 | }); 78 | }, 79 | http: function (model, workflow, callback) { 80 | var action = workflow.get('action'); 81 | if (!action.url) { 82 | return callback('No action url defined!'); 83 | } 84 | 85 | var wf_opts = {}; 86 | if (action.http) { 87 | wf_opts = action.http; 88 | } 89 | 90 | var ajax_options = jQuery.extend({ 91 | url: action.url, 92 | type: 'POST', 93 | data: model.toJSON(), 94 | success: function () { 95 | model.fetch({ 96 | success: function (model) { 97 | callback(null, model); 98 | }, 99 | error: function (model, err) { 100 | callback(err, model); 101 | } 102 | }); 103 | } 104 | }, wf_opts); 105 | 106 | jQuery.ajax(ajax_options); 107 | } 108 | } 109 | }, 110 | 111 | _init: function () { 112 | this._renderers = {}; 113 | this._action_types = {}; 114 | 115 | this._parseRenderersAndTypes(); 116 | 117 | this._last_instance = null; 118 | 119 | this.ModelWorkflowModel = Backbone.Model.extend({ 120 | defaults: { 121 | name: '', 122 | label: '', 123 | type: 'button', 124 | action: { 125 | type: 'backbone_save' 126 | } 127 | } 128 | }); 129 | 130 | this.workflows = {}; 131 | 132 | var widget = this; 133 | jQuery(this.element).on('midgardeditableactivated', function (event, options) { 134 | widget._fetchWorkflows(options.instance); 135 | }); 136 | }, 137 | 138 | _fetchWorkflows: function (model) { 139 | var widget = this; 140 | if (model.isNew()) { 141 | widget._trigger('changed', null, { 142 | instance: model, 143 | workflows: [] 144 | }); 145 | return; 146 | } 147 | 148 | if (widget._last_instance == model) { 149 | if (widget.workflows[model.cid]) { 150 | widget._trigger('changed', null, { 151 | instance: model, 152 | workflows: widget.workflows[model.cid] 153 | }); 154 | } 155 | return; 156 | } 157 | widget._last_instance = model; 158 | 159 | if (widget.workflows[model.cid]) { 160 | widget._trigger('changed', null, { 161 | instance: model, 162 | workflows: widget.workflows[model.cid] 163 | }); 164 | return; 165 | } 166 | 167 | if (widget.options.url) { 168 | widget._fetchModelWorkflows(model); 169 | } else { 170 | var flows = new(widget._generateCollectionFor(model))([], {}); 171 | widget._trigger('changed', null, { 172 | instance: model, 173 | workflows: flows 174 | }); 175 | } 176 | }, 177 | 178 | _parseRenderersAndTypes: function () { 179 | var widget = this; 180 | jQuery.each(this.options.renderers, function (k, v) { 181 | widget.setRenderer(k, v); 182 | }); 183 | jQuery.each(this.options.action_types, function (k, v) { 184 | widget.setActionType(k, v); 185 | }); 186 | }, 187 | 188 | setRenderer: function (name, callbacks) { 189 | this._renderers[name] = callbacks; 190 | }, 191 | getRenderer: function (name) { 192 | if (!this._renderers[name]) { 193 | return false; 194 | } 195 | 196 | return this._renderers[name]; 197 | }, 198 | setActionType: function (name, callback) { 199 | this._action_types[name] = callback; 200 | }, 201 | getActionType: function (name) { 202 | return this._action_types[name]; 203 | }, 204 | 205 | prepareItem: function (model, workflow, final_cb) { 206 | var widget = this; 207 | 208 | var renderer = this.getRenderer(workflow.get("type")); 209 | var action_type_cb = this.getActionType(workflow.get("action").type); 210 | 211 | return renderer.call(this, model, workflow, action_type_cb, function (err, m) { 212 | delete widget.workflows[model.cid]; 213 | widget._last_instance = null; 214 | if (workflow.get('action').type !== 'backbone_destroy') { 215 | // Get an updated list of workflows 216 | widget._fetchModelWorkflows(model); 217 | } 218 | final_cb(err, m); 219 | }); 220 | }, 221 | 222 | _generateCollectionFor: function (model) { 223 | var collectionSettings = { 224 | model: this.ModelWorkflowModel 225 | }; 226 | if (this.options.url) { 227 | collectionSettings.url = this.options.url(model); 228 | } 229 | return Backbone.Collection.extend(collectionSettings); 230 | }, 231 | 232 | _fetchModelWorkflows: function (model) { 233 | if (model.isNew()) { 234 | return; 235 | } 236 | var widget = this; 237 | 238 | widget.workflows[model.cid] = new(this._generateCollectionFor(model))([], {}); 239 | widget.workflows[model.cid].fetch({ 240 | success: function (collection) { 241 | widget.workflows[model.cid].reset(collection.models); 242 | 243 | widget._trigger('changed', null, { 244 | instance: model, 245 | workflows: widget.workflows[model.cid] 246 | }); 247 | }, 248 | error: function (model, err) { 249 | //console.log('error fetching flows', err); 250 | } 251 | }); 252 | } 253 | }); 254 | })(jQuery); 255 | -------------------------------------------------------------------------------- /src/metadataWidgets/jquery.Midgard.midgardGeo.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 Martin Holzhauer 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | */ 7 | (function (jQuery, undefined) { 8 | /*global OpenLayers:false */ 9 | // Run JavaScript in strict mode 10 | 'use strict'; 11 | 12 | // This widget allows editing geocoordinates with the help of openlayers 13 | // and per default layer OSM 14 | jQuery.widget('Midgard.midgardGeo', { 15 | options:{ 16 | layer:null, 17 | map:null, 18 | coordSystem:'EPSG:4326', 19 | defaultCenter: null, 20 | defaultZoomLevel: 3, 21 | geoProperty: 'http://schema.org/geo', 22 | geoCoordinateType: 'http://schema.org/GeoCoordinates', 23 | geoLonProperty: 'http://schema.org/longitude', 24 | geoLatProperty: 'http://schema.org/latitude', 25 | marker: { 26 | url: 'http://www.openlayers.org/dev/img/marker.png', 27 | size: {w:21, h:25}, 28 | offset: {w:-10, h:-25} //-(size.w / 2), -size.h 29 | } 30 | }, 31 | data : {}, 32 | coordsObj : null, 33 | 34 | /** 35 | * activate mapwidget 36 | * 37 | * @param data 38 | */ 39 | activate: function (data) { 40 | this.data = data; 41 | this.coordsObj = null; 42 | 43 | var geo = this.data.entity.get(this.options.geoProperty); 44 | 45 | if(_.isUndefined(geo)) { 46 | var types = this.data.entity.attributes['@type']; 47 | if(!_.isArray(types)) { 48 | types = [types]; 49 | } 50 | 51 | if(_.indexOf(types, '<' + this.options.geoCoordinateType + '>') > 0) { 52 | this.coordsObj = this.data.entity; 53 | } 54 | } else { 55 | this.coordsObj = geo.models[0]; 56 | } 57 | 58 | if(_.isNull(this.coordsObj)){ 59 | this.element.hide(); 60 | return; 61 | } else { 62 | this.element.show(); 63 | } 64 | 65 | 66 | var lat = parseFloat(this.coordsObj.get(this.options.geoLatProperty)), 67 | lon = parseFloat(this.coordsObj.get(this.options.geoLonProperty)); 68 | 69 | this.centerMap(lon, lat); 70 | }, 71 | 72 | /** 73 | * create the map object 74 | * 75 | * @private 76 | */ 77 | _createMap: function() { 78 | if (!_.isNull(this.options.map)) { 79 | return; 80 | } 81 | var that = this, 82 | mapDiv = jQuery('
    ', { 83 | id:'midgardGeoMap', 84 | style:"height:200px; width:300px" 85 | }); 86 | this.element.append(mapDiv); 87 | this.options.map = new OpenLayers.Map('midgardGeoMap'); 88 | 89 | 90 | if (_.isNull(this.options.layer)) { 91 | this.options.layer = new OpenLayers.Layer.OSM("OSM"); 92 | } 93 | 94 | this.options.map.addLayer(this.options.layer); 95 | 96 | this.options.markers = new OpenLayers.Layer.Markers("Markers"); 97 | this.options.map.addLayer(this.options.markers); 98 | 99 | 100 | OpenLayers.Control.Click = OpenLayers.Class(OpenLayers.Control, { 101 | defaultHandlerOptions:{ 102 | 'single':true, 103 | 'double':false, 104 | 'pixelTolerance':0, 105 | 'stopSingle':false, 106 | 'stopDouble':false 107 | }, 108 | 109 | initialize:function (options) { 110 | this.handlerOptions = OpenLayers.Util.extend( 111 | {}, this.defaultHandlerOptions 112 | ); 113 | OpenLayers.Control.prototype.initialize.apply( 114 | this, arguments 115 | ); 116 | this.handler = new OpenLayers.Handler.Click( 117 | this, { 118 | 'click':function (e) { 119 | that.mapClick(e); 120 | } 121 | }, this.handlerOptions 122 | ); 123 | } 124 | }); 125 | 126 | 127 | var click = new OpenLayers.Control.Click(); 128 | this.options.map.addControl(click); 129 | click.activate(); 130 | 131 | var center = this.options.defaultCenter.clone(); 132 | center.transform( 133 | new OpenLayers.Projection(this.options.coordSystem), 134 | this.options.map.getProjectionObject() 135 | ); 136 | 137 | this.options.map.setCenter( 138 | center, this.options.defaultZoomLevel 139 | ); 140 | }, 141 | 142 | mapClick:function (e) { 143 | var lonlat = this.options.map.getLonLatFromPixel(e.xy); 144 | lonlat.transform(this.options.map.getProjectionObject(), new OpenLayers.Projection(this.options.coordSystem)); 145 | 146 | var panTo = lonlat.clone(); 147 | this.centerMap(panTo.lon, panTo.lat); 148 | this.setCoordinates(lonlat.lat, lonlat.lon); 149 | }, 150 | 151 | disable:function () { 152 | 153 | }, 154 | 155 | /** 156 | * set coordinates to the model 157 | * 158 | * @param lat 159 | * @param lon 160 | */ 161 | setCoordinates:function (lat, lon) { 162 | var geo = this.data.entity.get(this.options.geoProperty), 163 | coordsModel = geo.models[0]; 164 | 165 | coordsModel.set(this.options.geoLatProperty, lat); 166 | coordsModel.set(this.options.geoLonProperty, lon); 167 | }, 168 | 169 | /** 170 | * widget init 171 | * 172 | * @private 173 | */ 174 | _init:function () { 175 | this.element.hide(); 176 | this.element.append( jQuery('

    GEO

    ') ); 177 | if(_.isNull(this.options.defaultCenter)){ 178 | this.options.defaultCenter = new OpenLayers.LonLat(0, 0); 179 | } 180 | this._createMap(); 181 | }, 182 | 183 | /** 184 | * coordinates should be given in the default coordiante system from config 185 | * 186 | * @param lon 187 | * @param lat 188 | */ 189 | centerMap:function (lon, lat) { 190 | var center = new OpenLayers.LonLat(lon, lat).transform( 191 | new OpenLayers.Projection(this.options.coordSystem), 192 | this.options.map.getProjectionObject() 193 | ); 194 | 195 | if (this.options.centermark) { 196 | this.options.centermark.destroy(); 197 | } 198 | 199 | var size = new OpenLayers.Size( 200 | this.options.marker.size.w , 201 | this.options.marker.size.h 202 | ); 203 | var offset = new OpenLayers.Pixel( 204 | this.options.marker.offset.w , 205 | this.options.marker.offset.h 206 | ); 207 | var icon = new OpenLayers.Icon(this.options.marker.url, size, offset); 208 | this.options.centermark = new OpenLayers.Marker(center, icon); 209 | this.options.markers.addMarker(this.options.centermark); 210 | 211 | this.options.map.panTo(center); 212 | } 213 | }); 214 | })(jQuery); 215 | -------------------------------------------------------------------------------- /src/metadataWidgets/jquery.Midgard.midgardTags.js: -------------------------------------------------------------------------------- 1 | /* 2 | // Create.js - On-site web editing interface 3 | // (c) 2012 IKS Consortium 4 | // Create may be freely distributed under the MIT license. 5 | // For all details and documentation: 6 | // http://createjs.org/ 7 | */ 8 | (function (jQuery, undefined) { 9 | // Run JavaScript in strict mode 10 | /*global jQuery:false _:false window:false */ 11 | 'use strict'; 12 | 13 | jQuery.widget('Midgard.midgardTags', { 14 | enhanced: false, 15 | 16 | options: { 17 | predicate: 'skos:related', 18 | vie: null, 19 | templates: { 20 | tags: '

    <%= label %>

    ' 21 | }, 22 | localize: function (id, language) { 23 | return window.midgardCreate.localize(id, language); 24 | }, 25 | language: null 26 | }, 27 | 28 | _init: function () { 29 | this.vie = this.options.vie; 30 | }, 31 | 32 | activate: function (data) { 33 | // An editable has been activated. Prepare the tag editor for the 34 | // entity 35 | var inputs = this._render(data.entity); 36 | this.loadTags(data.entity, data.predicate, inputs); 37 | }, 38 | 39 | // Convert to reference URI as needed 40 | _normalizeSubject: function(subject) { 41 | if (this.vie.entities.isReference(subject)) { 42 | return subject; 43 | } 44 | 45 | if (subject.substr(0, 7) !== 'http://') { 46 | subject = 'urn:tag:' + subject; 47 | } 48 | 49 | subject = this.vie.entities.toReference(subject); 50 | return subject; 51 | }, 52 | 53 | _tagLabel: function (subject) { 54 | subject = this.vie.entities.fromReference(subject); 55 | 56 | if (subject.substr(0, 8) === 'urn:tag:') { 57 | subject = subject.substr(8, subject.length - 1); 58 | } 59 | 60 | if (subject.substring(0, 7) == 'http://') { 61 | subject = subject.substr(subject.lastIndexOf('/') + 1, subject.length - 1); 62 | subject = subject.replace(/_/g, ' '); 63 | } 64 | return subject; 65 | }, 66 | 67 | // Centralized method for adding new tags to an entity 68 | // regardless of whether they come from this widget 69 | // or Annotate.js 70 | addTag: function (entity, subject, label, type) { 71 | if (label === undefined) { 72 | label = this._tagLabel(subject); 73 | } 74 | 75 | subject = this._normalizeSubject(subject); 76 | var tags = entity.get(this.options.predicate); 77 | if (tags && tags.isCollection && tags.get(subject)) { 78 | return; 79 | } 80 | 81 | if (type && !entity.isReference(type)) { 82 | type = entity.toReference(type); 83 | } 84 | 85 | var tagEntity = this.vie.entities.addOrUpdate({ 86 | '@subject': subject, 87 | 'rdfs:label': label, 88 | '@type': type 89 | }); 90 | 91 | if (!tags) { 92 | entity.set(this.options.predicate, tagEntity); 93 | return; 94 | } 95 | tags.addOrUpdate(tagEntity); 96 | }, 97 | 98 | removeTag: function (entity, subject) { 99 | var tags = entity.get(this.options.predicate); 100 | if (!tags) { 101 | return; 102 | } 103 | 104 | subject = this._normalizeSubject(subject); 105 | var tag = tags.get(subject); 106 | if (!tag) { 107 | return; 108 | } 109 | 110 | tags.remove(subject); 111 | }, 112 | 113 | // Listen for accepted annotations from Annotate.js if that 114 | // is in use and register them as tags 115 | _listenAnnotate: function (entity, entityElement) { 116 | var widget = this; 117 | entityElement.on('annotateselect', function (event, data) { 118 | widget.addTag(entity, data.linkedEntity.uri, data.linkedEntity.label, data.linkedEntity.type[0]); 119 | }); 120 | 121 | entityElement.on('annotateremove', function (event, data) { 122 | widget.removeTag(entity, data.linkedEntity.uri); 123 | }); 124 | }, 125 | 126 | _render: function (entity) { 127 | this.element.empty(); 128 | var articleTags = jQuery(_.template(this.options.templates.tags, { 129 | type: 'article', 130 | label: this.options.localize('Item tags', this.options.language) 131 | })); 132 | var suggestedTags = jQuery(_.template(this.options.templates.tags, { 133 | type: 'suggested', 134 | label: this.options.localize('Suggested tags', this.options.language) 135 | })); 136 | 137 | // Tags plugin requires IDs to exist 138 | jQuery('input', articleTags).attr('id', 'articleTags-' + entity.cid); 139 | jQuery('input', suggestedTags).attr('id', 'suggestedTags-' + entity.cid); 140 | 141 | this.element.append(articleTags); 142 | this.element.append(suggestedTags); 143 | 144 | this._renderInputs(entity, articleTags, suggestedTags); 145 | return { 146 | tags: articleTags, 147 | suggested: suggestedTags 148 | }; 149 | }, 150 | 151 | _renderInputs: function (entity, articleTags, suggestedTags) { 152 | var widget = this; 153 | var subject = entity.getSubject(); 154 | 155 | articleTags.tagsInput({ 156 | width: 'auto', 157 | height: 'auto', 158 | onAddTag: function (tag) { 159 | widget.addTag(entity, tag); 160 | }, 161 | onRemoveTag: function (tag) { 162 | widget.removeTag(entity, tag); 163 | }, 164 | defaultText: this.options.localize('add a tag', this.options.language) 165 | }); 166 | 167 | var selectSuggested = function () { 168 | var tag = jQuery.trim(jQuery(this).text()); 169 | widget.addTag(entity, tag); 170 | suggestedTags.removeTag(tag); 171 | }; 172 | 173 | suggestedTags.tagsInput({ 174 | width: 'auto', 175 | height: 'auto', 176 | interactive: false, 177 | onAddTag: function (tag) { 178 | jQuery('.tag span', suggestedTags).off('click', selectSuggested); 179 | jQuery('.tag span', suggestedTags).on('click', selectSuggested); 180 | }, 181 | onRemoveTag: function (tag) { 182 | jQuery('.tag span', suggestedTags).off('click', selectSuggested); 183 | jQuery('.tag span', suggestedTags).on('click', selectSuggested); 184 | }, 185 | remove: false 186 | }); 187 | }, 188 | 189 | _getTagStrings: function (tags) { 190 | var tagArray = []; 191 | 192 | if (_.isString(tags)) { 193 | tagArray.push(tags); 194 | return tagArray; 195 | } 196 | 197 | if (tags.isCollection) { 198 | tags.each(function (tag) { 199 | tagArray.push(tag.get('rdfs:label')); 200 | }); 201 | return tagArray; 202 | } 203 | 204 | _.each(tags, function (tag) { 205 | tagArray.push(this._tagLabel(tag)); 206 | }, this); 207 | return tagArray; 208 | }, 209 | 210 | loadTags: function (entity, predicate, inputs) { 211 | var widget = this; 212 | 213 | // Populate existing tags from entity 214 | var tags = entity.get(this.options.predicate); 215 | if (tags) { 216 | var tagArray = this._getTagStrings(tags); 217 | _.each(tagArray, inputs.tags.addTag, inputs.tags); 218 | } 219 | 220 | if (this.vie.services.stanbol) { 221 | //widget.enhance(); 222 | } else { 223 | jQuery('.suggestedTags', widget.element).hide(); 224 | } 225 | }, 226 | 227 | _getLabelLang: function (labels) { 228 | if (!_.isArray(labels)) { 229 | return null; 230 | } 231 | 232 | var langLabel; 233 | 234 | _.each(labels, function (label) { 235 | if (label['@language'] === 'en') { 236 | langLabel = label['@value']; 237 | } 238 | }); 239 | 240 | return langLabel; 241 | }, 242 | 243 | _addEnhancement: function (entity, enhancement) { 244 | if (!enhancement.isEntity) { 245 | return; 246 | } 247 | 248 | var label = this._getLabelLang(enhancement.get('rdfs:label')); 249 | if (!label) { 250 | return; 251 | } 252 | 253 | var tags = entity.get(this.options.predicate); 254 | if (tags && tags.isCollection && tags.indexOf(enhancement) !== -1) { 255 | return; 256 | } 257 | 258 | this.suggestedTags.addTag(label); 259 | }, 260 | 261 | enhance: function (entity, entityElement) { 262 | if (this.enhanced) { 263 | return; 264 | } 265 | this.enhanced = true; 266 | 267 | var widget = this; 268 | 269 | // load suggested tags 270 | this.vie.analyze({ 271 | element: jQuery('[property]', entityElement) 272 | }).using(['stanbol']).execute().success(function (enhancements) { 273 | _.each(enhancements, function (enhancement) { 274 | widget._addEnhancement(entity, enhancement); 275 | }); 276 | }).fail(function (xhr) { 277 | // console.log(xhr); 278 | }); 279 | } 280 | }); 281 | })(jQuery); 282 | -------------------------------------------------------------------------------- /src/midgardCreate.localize.js: -------------------------------------------------------------------------------- 1 | if (window.midgardCreate === undefined) { 2 | window.midgardCreate = {}; 3 | } 4 | 5 | window.midgardCreate.localize = function (id, language) { 6 | if (!window.midgardCreate.locale) { 7 | // No localization files loaded, return as-is 8 | return id; 9 | } 10 | if (window.midgardCreate.locale[language] && window.midgardCreate.locale[language][id]) { 11 | return window.midgardCreate.locale[language][id]; 12 | } 13 | if (window.midgardCreate.locale.en[id]) { 14 | return window.midgardCreate.locale.en[id]; 15 | } 16 | return id; 17 | }; 18 | -------------------------------------------------------------------------------- /test/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Create.js browser tests 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 |

    Unit tests for Create.js - using QUnit

    56 |

    57 |
    58 |

    59 |
      60 |
      61 |
      62 |
      63 |
      64 |
      65 |

      Hello, world

      66 |
      67 |
      68 |
      69 |
      70 |
      71 |
      72 |

      Hello, world

      73 |
      74 |
      75 |
      76 |
      77 |

      Hello, world

      78 |

      Henri Bergius

      79 |
      80 |
      81 |
      82 |
      83 |

      Hello, world

      84 |

      Henri Bergius

      85 |
      86 |
      87 |
      88 |
      89 |
      90 |
      91 |
      92 |
      93 |
      94 |
      95 |
      96 |
      97 |
      Foo
      98 |
      99 |
      100 |
      101 |
      102 |
      Foo
      103 |
      104 |
      105 |
      106 |
      107 |
      108 |

      Foo

      109 |
      110 |
      111 |
      112 |
      113 |
      114 |
      115 |

      Foo

      116 |
      117 |
      118 |
      119 |
      120 |
      121 |
      122 |

      Foo

      123 |
      124 |
      125 |
      126 |
      127 |
      128 |
      129 |

      Foo

      130 |
      131 |
      132 |
      133 |
      134 | 135 | 136 | -------------------------------------------------------------------------------- /test/midgardCreate.js: -------------------------------------------------------------------------------- 1 | module('midgardCreate'); 2 | 3 | test('Create widget registered', function () { 4 | equal(typeof jQuery('body').midgardCreate, 'function'); 5 | }); 6 | 7 | test('Create instantiation w/o VIE', function () { 8 | var fixture = jQuery('.create-instance'); 9 | fixture.midgardCreate(); 10 | var instance = fixture.data('Midgard-midgardCreate'); 11 | ok(instance); 12 | 13 | // Check some of the autoinitialization 14 | ok(instance.vie); 15 | ok(instance.vie.hasService('rdfa')); 16 | }); 17 | 18 | test('Create instantiation and destruction', function () { 19 | var fixture = jQuery('.create-instance-destroy'); 20 | fixture.midgardCreate(); 21 | 22 | // Check that all Create.js widgets have been instantiated 23 | ok(fixture.data('Midgard-midgardCreate'), 'Create instance'); 24 | ok(fixture.data('Midgard-midgardNotifications'), 'Notifications instance'); 25 | ok(fixture.data('Midgard-midgardWorkflows'), 'Workflows instance'); 26 | ok(fixture.data('Midgard-midgardToolbar'), 'Toolbar instance'); 27 | ok(fixture.data('Midgard-midgardStorage'), 'Storage instance'); 28 | 29 | jQuery('[about]', fixture).each(function () { 30 | ok(jQuery(this).data('Midgard-midgardEditable'), 'Editable instance'); 31 | }); 32 | 33 | fixture.midgardCreate('destroy'); 34 | 35 | // Check that all the widget instances have been cleaned up 36 | equal(fixture.data('Midgard-midgardCreate'), undefined); 37 | equal(fixture.data('Midgard-midgardNotifications'), undefined); 38 | equal(fixture.data('Midgard-midgardWorkflows'), undefined); 39 | equal(fixture.data('Midgard-midgardToolbar'), undefined); 40 | equal(fixture.data('Midgard-midgardStorage'), undefined); 41 | 42 | jQuery('[about]', fixture).each(function () { 43 | equal(jQuery(this).data('Midgard-midgardEditable'), undefined); 44 | }); 45 | 46 | /* 47 | * TODO: enable when jQuery UI 1.9 is out 48 | throws(function () { 49 | fixture.midgardCreate('configureEditor', 'aloha', 'alohaWidget', {}); 50 | }, 'Throws exception because midgardCreate instance has been destroyed'); 51 | */ 52 | }); 53 | 54 | test('Create instantiation with VIE', function () { 55 | var v = new VIE(); 56 | var fixture = jQuery('.create-instance-vie'); 57 | fixture.midgardCreate({ 58 | vie: v 59 | }); 60 | 61 | var instance = fixture.data('Midgard-midgardCreate'); 62 | ok(instance); 63 | 64 | // Check that Create uses *our* VIE 65 | ok(instance.vie); 66 | equal(instance.vie, v); 67 | 68 | // Check that VIE's DOM parsing service supplies the methods we need 69 | ok(instance.domService); 70 | ok(v.hasService(instance.options.domService)); 71 | equal(instance.domService, v.service(instance.options.domService)); 72 | ok(_.isFunction(instance.domService.findSubjectElements)); 73 | }); 74 | 75 | test('Create URL callback registration', function () { 76 | expect(3); 77 | var fixture = jQuery('.create-url-callback'); 78 | 79 | fixture.bind('midgardeditableenable', function (event, data) { 80 | ok(data.instance); 81 | ok(data.entityElement); 82 | equal(data.instance.url(), 'foo'); 83 | }); 84 | 85 | fixture.midgardCreate({ 86 | url: function () { return 'foo'; }, 87 | state: 'edit' 88 | }); 89 | }); 90 | 91 | test('Create edit events', function () { 92 | expect(27); 93 | var fixture = jQuery('.create-edit-events'); 94 | 95 | fixture.bind('midgardcreatestatechange', function (event, data) { 96 | ok(data.state); 97 | equal(data.state, 'edit'); 98 | }); 99 | 100 | fixture.bind('midgardeditableenable', function (event, data) { 101 | // Ensure backwards compatibility. 102 | ok(data.instance); 103 | ok(data.entityElement); 104 | 105 | ok(data.entity, 'enabled properties have the Backbone model instance for the entity'); 106 | ok(data.editableEntity, 'enabled properties have the EditableEntity widget object for the entity'); 107 | ok(data.entityElement, 'enabled properties have the DOM element for the entity'); 108 | }); 109 | 110 | // We have two properties, so this will be called twice 111 | fixture.bind('midgardeditableenableproperty', function (event, data) { 112 | // Ensure backwards compatibility. 113 | ok(data.predicate); 114 | ok(data.instance); 115 | ok(data.element); 116 | ok(data.entityElement); 117 | 118 | ok(data.entity, 'enabled properties have the Backbone model instance for the entity'); 119 | ok(data.editableEntity, 'enabled properties have the EditableEntity widget object for the entity'); 120 | ok(data.entityElement, 'enabled properties have the DOM element for the entity'); 121 | ok(data.predicate, 'enabled properties have the predicate of the property'); 122 | ok(data.propertyEditor, 'enabled properties have the property editor for the property'); 123 | ok(data.propertyElement, 'enabled properties have the DOM element for the property'); 124 | }); 125 | 126 | fixture.midgardCreate({ 127 | state: 'edit' 128 | }); 129 | }); 130 | 131 | test('Create state change events', function () { 132 | expect(41); 133 | var fixture = jQuery('.create-state-events'); 134 | 135 | var previous = null; 136 | fixture.bind('midgardcreatestatechange', function (event, data) { 137 | ok(data.state, 'State change events provide a state value'); 138 | if (previous === 'browse') { 139 | equal(data.state, 'edit', 'from browse we go to edit state'); 140 | previous = 'edit'; 141 | } else { 142 | equal(data.state, 'browse', 'from edit we got to browse state'); 143 | previous = 'browse'; 144 | } 145 | }); 146 | 147 | // Will be called once, when we go to edit state 148 | fixture.bind('midgardeditableenable', function (event, data) { 149 | // Ensure backwards compatibility. 150 | ok(data.instance, 'enabled editables provide entity instance'); 151 | ok(data.entityElement, 'enabled editables provide the entity element'); 152 | 153 | ok(data.entity, 'enabled properties have the Backbone model instance for the entity'); 154 | ok(data.editableEntity, 'enabled properties have the EditableEntity widget object for the entity'); 155 | ok(data.entityElement, 'enabled properties have the DOM element for the entity'); 156 | }); 157 | 158 | // Will be called twice, initially and then when returning to browse state 159 | fixture.bind('midgardeditabledisable', function (event, data) { 160 | // Ensure backwards compatibility. 161 | ok(data.instance, 'disabled editables provide entity instance'); 162 | ok(data.entityElement, 'disabled editables provide the entity element'); 163 | 164 | ok(data.entity, 'enabled properties have the Backbone model instance for the entity'); 165 | ok(data.editableEntity, 'enabled properties have the EditableEntity widget object for the entity'); 166 | ok(data.entityElement, 'enabled properties have the DOM element for the entity'); 167 | }); 168 | 169 | // We have two properties, so this will be called twice 170 | fixture.bind('midgardeditableenableproperty', function (event, data) { 171 | // Ensure backwards compatibility. 172 | ok(data.property, 'enabled properties have property name'); 173 | ok(data.instance, 'enabled properties have entity instance'); 174 | ok(data.element, 'enabled properties have property element'); 175 | ok(data.entityElement, 'enabled properties have entity element'); 176 | 177 | ok(data.entity, 'enabled properties have the Backbone model instance for the entity'); 178 | ok(data.editableEntity, 'enabled properties have the EditableEntity widget object for the entity'); 179 | ok(data.entityElement, 'enabled properties have the DOM element for the entity'); 180 | ok(data.predicate, 'enabled properties have the predicate of the property'); 181 | ok(data.propertyEditor, 'enabled properties have the property editor for the property'); 182 | ok(data.propertyElement, 'enabled properties have the DOM element for the property'); 183 | }); 184 | 185 | // Start in browse state 186 | fixture.midgardCreate(); 187 | // Enter edit state 188 | fixture.midgardCreate('setState', 'edit'); 189 | // Return to browse state 190 | fixture.midgardCreate('setState', 'browse'); 191 | }); 192 | 193 | test('Create toolbar minimize / maximize', function () { 194 | var fixture = jQuery('.create-toolbar-state'); 195 | fixture.midgardCreate(); 196 | 197 | // Initially the full toolbar should be shown 198 | equal(jQuery('div.create-ui-toolbar-wrapper:visible', fixture).length, 1); 199 | equal(jQuery('div.create-ui-logo:visible', fixture).length, 1); 200 | 201 | var previous = 'full'; 202 | fixture.bind('midgardtoolbarstatechange', function (event, data) { 203 | ok(data.display, 'toolbar change events should communicate display state'); 204 | if (previous === 'full') { 205 | equal(data.display, 'minimized', 'after full the toolbar should get minimized'); 206 | previous = 'minimized'; 207 | } else { 208 | equal(data.display, 'full', 'after minimized the toolbar should be maximized'); 209 | previous = 'full'; 210 | } 211 | start(); 212 | }); 213 | 214 | // Click the Logo to minimize 215 | stop(2); 216 | jQuery('div.create-ui-logo a.create-ui-toggle', fixture).click(); 217 | 218 | setTimeout(function () { 219 | equal(jQuery('div.create-ui-toolbar-wrapper:visible', fixture).length, 0, 'after minimization there should be no visible toolbars'); 220 | equal(jQuery('div.create-ui-toolbar-wrapper:hidden', fixture).length, 1, 'after minimization there should be no visible toolbars'); 221 | equal(jQuery('div.create-ui-logo:visible', fixture).length, 1, 'Create.js logo should remain visible'); 222 | start(); 223 | 224 | // Click the Logo to maximize again 225 | stop(2); 226 | jQuery('div.create-ui-logo a.create-ui-toggle', fixture).click(); 227 | 228 | setTimeout(function () { 229 | equal(jQuery('div.create-ui-toolbar-wrapper:hidden', fixture).length, 0); 230 | equal(jQuery('div.create-ui-toolbar-wrapper:visible', fixture).length, 1); 231 | equal(jQuery('div.create-ui-logo:visible', fixture).length, 1, 'Create.js logo should remain visible'); 232 | start(); 233 | }, 500); 234 | }, 500); 235 | }); 236 | -------------------------------------------------------------------------------- /test/midgardEditable.js: -------------------------------------------------------------------------------- 1 | module('midgardEditable'); 2 | 3 | test('Editable widget', function() { 4 | equal(typeof jQuery('body').midgardEditable, 'function'); 5 | }); 6 | 7 | test('Editable instance', function () { 8 | var fixture = jQuery('.edit-instance'); 9 | 10 | var v = new VIE(); 11 | v.use(new v.RdfaService()); 12 | 13 | fixture.midgardEditable({ 14 | vie: v 15 | }); 16 | 17 | var instance = fixture.data('Midgard-midgardEditable'); 18 | ok(instance); 19 | 20 | // Check VIE 21 | ok(instance.vie); 22 | equal(instance.vie, v); 23 | ok(instance.domService); 24 | equal(instance.domService, v.service(instance.options.domService)); 25 | ok(_.isFunction(instance.domService.findPredicateElements)); 26 | ok(_.isFunction(instance.domService.getElementPredicate)); 27 | ok(_.isArray(instance.domService.views)); 28 | }); 29 | 30 | test('Editable state change', function () { 31 | var fixture = jQuery('.edit-states'); 32 | 33 | var v = new VIE(); 34 | v.use(new v.RdfaService()); 35 | 36 | fixture.midgardEditable({ 37 | vie: v, 38 | disabled: true 39 | }); 40 | 41 | var instance = fixture.data('Midgard-midgardEditable'); 42 | ok(instance); 43 | 44 | equal(instance.getState(), 'inactive'); 45 | 46 | stop(); 47 | fixture.one('midgardeditablestatechange', function (event, data) { 48 | // Check state change values 49 | ok(data.current); 50 | equal(data.current, 'candidate'); 51 | ok(data.previous); 52 | equal(data.previous, 'inactive'); 53 | equal(data.predicate, null); 54 | 55 | // Check context 56 | ok(data.context); 57 | ok(data.context.foo); 58 | equal(data.context.foo, 'bar'); 59 | 60 | // Check regular event params 61 | ok(data.entity); 62 | equal(data.entity.getSubjectUri(), 'states'); 63 | ok(data.editableEntity); 64 | equal(data.editableEntity, instance); 65 | ok(data.entityElement); 66 | equal(data.entityElement.get(0), fixture.get(0)); 67 | 68 | // Check deprecated event params 69 | ok(data.editable); 70 | equal(data.editable, data.editableEntity); 71 | ok(data.element); 72 | equal(data.element, data.entityElement); 73 | ok(data.instance); 74 | equal(data.instance, data.entity); 75 | start(); 76 | }); 77 | fixture.midgardEditable('setState', 'candidate', null, { 78 | foo: 'bar' 79 | }); 80 | }); 81 | 82 | test('Editable decorators', function () { 83 | var fixture = jQuery('.edit-decorators'); 84 | 85 | var v = new VIE(); 86 | v.use(new v.RdfaService()); 87 | 88 | stop(3); 89 | 90 | var entityDecorator = function (data) { 91 | ok(data); 92 | ok(data.entity); 93 | equal(data.entity.getSubjectUri(), 'decorators'); 94 | ok(data.editableEntity); 95 | ok(data.entityElement); 96 | equal(data.entityElement.get(0), fixture.get(0)); 97 | start(); 98 | }; 99 | 100 | var propertyDecorator = function (data) { 101 | ok(data); 102 | ok(data.predicate); 103 | equal(data.predicate, 'dcterms:title'); 104 | ok(data.propertyEditor); 105 | ok(data.propertyElement); 106 | equal(data.propertyElement.get(0), jQuery('[property]', fixture).get(0)); 107 | start(); 108 | }; 109 | 110 | fixture.midgardEditable({ 111 | vie: v, 112 | decorateEditableEntity: entityDecorator, 113 | decoratePropertyEditor: propertyDecorator 114 | }); 115 | 116 | fixture.one('midgardeditablestatechange', function (event, data) { 117 | ok(data.entity); 118 | ok(data.current); 119 | equal(data.current, 'active'); 120 | ok(data.previous); 121 | equal(data.previous, 'candidate'); 122 | ok(data.predicate); 123 | equal(data.predicate, 'dcterms:title'); 124 | start(); 125 | }); 126 | 127 | window.setTimeout(function () { 128 | jQuery('[property]', fixture).focus(); 129 | }, 20); 130 | }); 131 | 132 | test('Editable collection', function() { 133 | var fixture = jQuery('#qunit-fixture .edit-add'); 134 | var v = new VIE(); 135 | v.use(new v.RdfaService()); 136 | v.entities.on('add', function (entity) { 137 | entity.url = function () { return entity.getSubjectUri(); }; 138 | }); 139 | 140 | var enabled = 0; 141 | var checkEnabled = function(event, options) { 142 | enabled++; 143 | equal(options.property, 'dcterms:title'); 144 | 145 | if (options.instance.isNew()) { 146 | equal(options.instance.get('@type').id, ''); 147 | } 148 | }; 149 | fixture.bind('midgardeditableenableproperty', checkEnabled); 150 | 151 | v.service('rdfa').findSubjectElements(fixture).each(function () { 152 | jQuery(this).midgardEditable({ 153 | disabled: false, 154 | vie: v 155 | }); 156 | }); 157 | 158 | stop(); 159 | jQuery('.midgard-create-add', fixture).click(); 160 | 161 | setTimeout(function() { 162 | if (enabled < 2) { 163 | return; 164 | } 165 | start(); 166 | }, 500); 167 | }); 168 | 169 | test('Editable collection with type', function() { 170 | var fixture = jQuery('#qunit-fixture .edit-add-typed'); 171 | var v = new VIE(); 172 | v.use(new v.RdfaService()); 173 | v.entities.on('add', function (entity) { 174 | entity.url = function () { return entity.getSubjectUri(); }; 175 | }); 176 | v.service('rdfa').findSubjectElements(fixture).each(function () { 177 | jQuery(this).midgardEditable({ 178 | disabled: false, 179 | vie: v 180 | }); 181 | }); 182 | 183 | fixture.bind('midgardeditableenable', function(event, options) { 184 | ok(options.instance.isNew()); 185 | equal(options.instance.get('@type').id, ''); 186 | start(); 187 | }); 188 | 189 | jQuery('.midgard-create-add', fixture).click(); 190 | stop(); 191 | }); 192 | 193 | test('Editable collection edit/cancel', function() { 194 | var fixture = jQuery('#qunit-fixture .edit-edit-cancel'); 195 | var v = new VIE(); 196 | v.use(new v.RdfaService()); 197 | v.entities.on('add', function (entity) { 198 | entity.url = function () { return entity.getSubjectUri(); }; 199 | }); 200 | 201 | var enabled = 0; 202 | fixture.bind('midgardeditableenable', function(event, options) { 203 | enabled++; 204 | if (enabled < 2) { 205 | return; 206 | } 207 | equal(jQuery('[contenteditable="true"]', fixture).length, 1); 208 | start(); 209 | v.service('rdfa').findSubjectElements(fixture).each(function () { 210 | jQuery(this).midgardEditable({ 211 | disabled: true 212 | }); 213 | }); 214 | }); 215 | 216 | var disabled = 0; 217 | fixture.bind('midgardeditabledisable', function(event, options) { 218 | disabled++; 219 | if (disabled < 2) { 220 | return; 221 | } 222 | start(); 223 | equal(jQuery('[contenteditable="true"]', fixture).length, 0); 224 | }); 225 | 226 | stop(2); 227 | v.service('rdfa').findSubjectElements(fixture).each(function () { 228 | jQuery(this).midgardEditable({ 229 | disabled: false, 230 | vie: v 231 | }); 232 | }); 233 | }); 234 | 235 | test('Editable collection edit/add/cancel', function() { 236 | var fixture = jQuery('#qunit-fixture .edit-add-edit-cancel'); 237 | var v = new VIE(); 238 | v.use(new v.RdfaService()); 239 | v.entities.on('add', function (entity) { 240 | entity.url = function () { return entity.getSubjectUri(); }; 241 | }); 242 | 243 | equal(jQuery('[contenteditable="true"]', fixture).length, 0); 244 | v.service('rdfa').findSubjectElements(fixture).each(function () { 245 | jQuery(this).midgardEditable({ 246 | disabled: false, 247 | vie: v 248 | }); 249 | }); 250 | equal(jQuery('[contenteditable="true"]', fixture).length, 1); 251 | 252 | fixture.bind('midgardeditableenable', function(event, options) { 253 | ok(options.instance.isNew()); 254 | equal(options.instance.has('dcterms:title'), false); 255 | equal(jQuery('[contenteditable="true"]', fixture).length, 2); 256 | start(); 257 | v.service('rdfa').findSubjectElements(fixture).each(function () { 258 | jQuery(this).midgardEditable({ 259 | disabled: true 260 | }); 261 | }); 262 | }); 263 | 264 | var disabled = 0; 265 | fixture.bind('midgardeditabledisable', function(event, options) { 266 | disabled++; 267 | if (disabled < 3) { 268 | return; 269 | } 270 | start(); 271 | equal(jQuery('[contenteditable="true"]', fixture).length, 0); 272 | }); 273 | 274 | jQuery('.midgard-create-add', fixture).click(); 275 | stop(2); 276 | }); 277 | -------------------------------------------------------------------------------- /test/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /** 2 | * QUnit v1.9.0 - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2012 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * or GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | /** Font Family and Sizes */ 12 | 13 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 14 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; 15 | } 16 | 17 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 18 | #qunit-tests { font-size: smaller; } 19 | 20 | 21 | /** Resets */ 22 | 23 | #qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 24 | margin: 0; 25 | padding: 0; 26 | } 27 | 28 | 29 | /** Header */ 30 | 31 | #qunit-header { 32 | padding: 0.5em 0 0.5em 1em; 33 | 34 | color: #8699a4; 35 | background-color: #0d3349; 36 | 37 | font-size: 1.5em; 38 | line-height: 1em; 39 | font-weight: normal; 40 | 41 | border-radius: 5px 5px 0 0; 42 | -moz-border-radius: 5px 5px 0 0; 43 | -webkit-border-top-right-radius: 5px; 44 | -webkit-border-top-left-radius: 5px; 45 | } 46 | 47 | #qunit-header a { 48 | text-decoration: none; 49 | color: #c2ccd1; 50 | } 51 | 52 | #qunit-header a:hover, 53 | #qunit-header a:focus { 54 | color: #fff; 55 | } 56 | 57 | #qunit-testrunner-toolbar label { 58 | display: inline-block; 59 | padding: 0 .5em 0 .1em; 60 | } 61 | 62 | #qunit-banner { 63 | height: 5px; 64 | } 65 | 66 | #qunit-testrunner-toolbar { 67 | padding: 0.5em 0 0.5em 2em; 68 | color: #5E740B; 69 | background-color: #eee; 70 | } 71 | 72 | #qunit-userAgent { 73 | padding: 0.5em 0 0.5em 2.5em; 74 | background-color: #2b81af; 75 | color: #fff; 76 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 77 | } 78 | 79 | 80 | /** Tests: Pass/Fail */ 81 | 82 | #qunit-tests { 83 | list-style-position: inside; 84 | } 85 | 86 | #qunit-tests li { 87 | padding: 0.4em 0.5em 0.4em 2.5em; 88 | border-bottom: 1px solid #fff; 89 | list-style-position: inside; 90 | } 91 | 92 | #qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { 93 | display: none; 94 | } 95 | 96 | #qunit-tests li strong { 97 | cursor: pointer; 98 | } 99 | 100 | #qunit-tests li a { 101 | padding: 0.5em; 102 | color: #c2ccd1; 103 | text-decoration: none; 104 | } 105 | #qunit-tests li a:hover, 106 | #qunit-tests li a:focus { 107 | color: #000; 108 | } 109 | 110 | #qunit-tests ol { 111 | margin-top: 0.5em; 112 | padding: 0.5em; 113 | 114 | background-color: #fff; 115 | 116 | border-radius: 5px; 117 | -moz-border-radius: 5px; 118 | -webkit-border-radius: 5px; 119 | } 120 | 121 | #qunit-tests table { 122 | border-collapse: collapse; 123 | margin-top: .2em; 124 | } 125 | 126 | #qunit-tests th { 127 | text-align: right; 128 | vertical-align: top; 129 | padding: 0 .5em 0 0; 130 | } 131 | 132 | #qunit-tests td { 133 | vertical-align: top; 134 | } 135 | 136 | #qunit-tests pre { 137 | margin: 0; 138 | white-space: pre-wrap; 139 | word-wrap: break-word; 140 | } 141 | 142 | #qunit-tests del { 143 | background-color: #e0f2be; 144 | color: #374e0c; 145 | text-decoration: none; 146 | } 147 | 148 | #qunit-tests ins { 149 | background-color: #ffcaca; 150 | color: #500; 151 | text-decoration: none; 152 | } 153 | 154 | /*** Test Counts */ 155 | 156 | #qunit-tests b.counts { color: black; } 157 | #qunit-tests b.passed { color: #5E740B; } 158 | #qunit-tests b.failed { color: #710909; } 159 | 160 | #qunit-tests li li { 161 | padding: 5px; 162 | background-color: #fff; 163 | border-bottom: none; 164 | list-style-position: inside; 165 | } 166 | 167 | /*** Passing Styles */ 168 | 169 | #qunit-tests li li.pass { 170 | color: #3c510c; 171 | background-color: #fff; 172 | border-left: 10px solid #C6E746; 173 | } 174 | 175 | #qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } 176 | #qunit-tests .pass .test-name { color: #366097; } 177 | 178 | #qunit-tests .pass .test-actual, 179 | #qunit-tests .pass .test-expected { color: #999999; } 180 | 181 | #qunit-banner.qunit-pass { background-color: #C6E746; } 182 | 183 | /*** Failing Styles */ 184 | 185 | #qunit-tests li li.fail { 186 | color: #710909; 187 | background-color: #fff; 188 | border-left: 10px solid #EE5757; 189 | white-space: pre; 190 | } 191 | 192 | #qunit-tests > li:last-child { 193 | border-radius: 0 0 5px 5px; 194 | -moz-border-radius: 0 0 5px 5px; 195 | -webkit-border-bottom-right-radius: 5px; 196 | -webkit-border-bottom-left-radius: 5px; 197 | } 198 | 199 | #qunit-tests .fail { color: #000000; background-color: #EE5757; } 200 | #qunit-tests .fail .test-name, 201 | #qunit-tests .fail .module-name { color: #000000; } 202 | 203 | #qunit-tests .fail .test-actual { color: #EE5757; } 204 | #qunit-tests .fail .test-expected { color: green; } 205 | 206 | #qunit-banner.qunit-fail { background-color: #EE5757; } 207 | 208 | 209 | /** Result */ 210 | 211 | #qunit-testresult { 212 | padding: 0.5em 0.5em 0.5em 2.5em; 213 | 214 | color: #2b81af; 215 | background-color: #D2E0E6; 216 | 217 | border-bottom: 1px solid white; 218 | } 219 | #qunit-testresult .module-name { 220 | font-weight: bold; 221 | } 222 | 223 | /** Fixture */ 224 | 225 | #qunit-fixture { 226 | position: absolute; 227 | top: -10000px; 228 | left: -10000px; 229 | width: 1000px; 230 | height: 1000px; 231 | } 232 | -------------------------------------------------------------------------------- /test/qunit/run.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Wait until the test condition is true or a timeout occurs. Useful for waiting 3 | * on a server response or for a ui change (fadeIn, etc.) to occur. 4 | * 5 | * @param testFx javascript condition that evaluates to a boolean, 6 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 7 | * as a callback function. 8 | * @param onReady what to do when testFx condition is fulfilled, 9 | * it can be passed in as a string (e.g.: "1 == 1" or "$('#bar').is(':visible')" or 10 | * as a callback function. 11 | * @param timeOutMillis the max amount of time to wait. If not specified, 3 sec is used. 12 | */ 13 | function waitFor(testFx, onReady, timeOutMillis) { 14 | var maxtimeOutMillis = timeOutMillis ? timeOutMillis : 30001, //< Default Max Timout is 3s 15 | start = new Date().getTime(), 16 | condition = false, 17 | interval = setInterval(function() { 18 | if ( (new Date().getTime() - start < maxtimeOutMillis) && !condition ) { 19 | // If not time-out yet and condition not yet fulfilled 20 | condition = (typeof(testFx) === "string" ? eval(testFx) : testFx()); //< defensive code 21 | } else { 22 | if(!condition) { 23 | // If condition still not fulfilled (timeout but condition is 'false') 24 | console.log("'waitFor()' timeout"); 25 | phantom.exit(1); 26 | } else { 27 | // Condition fulfilled (timeout and/or condition is 'true') 28 | console.log("'waitFor()' finished in " + (new Date().getTime() - start) + "ms."); 29 | typeof(onReady) === "string" ? eval(onReady) : onReady(); //< Do what it's supposed to do once the condition is fulfilled 30 | clearInterval(interval); //< Stop this interval 31 | } 32 | } 33 | }, 100); //< repeat check every 250ms 34 | }; 35 | 36 | 37 | if (phantom.args.length === 0 || phantom.args.length > 2) { 38 | console.log('Usage: run-qunit.js URL'); 39 | phantom.exit(); 40 | } 41 | 42 | var page = new WebPage(); 43 | 44 | // Route "console.log()" calls from within the Page context to the main Phantom context (i.e. current "this") 45 | page.onConsoleMessage = function(msg) { 46 | console.log(msg); 47 | }; 48 | 49 | page.open(phantom.args[0], function(status){ 50 | if (status !== "success") { 51 | console.log("Unable to access network"); 52 | phantom.exit(); 53 | } else { 54 | waitFor(function(){ 55 | return page.evaluate(function(){ 56 | var el = document.getElementById('qunit-testresult'); 57 | if (el && el.innerText.match('completed')) { 58 | return true; 59 | } 60 | return false; 61 | }); 62 | }, function(){ 63 | var failedNum = page.evaluate(function(){ 64 | var el = document.getElementById('qunit-testresult'); 65 | console.log(el.innerText); 66 | try { 67 | return el.getElementsByClassName('failed')[0].innerHTML; 68 | } catch (e) { } 69 | return 10000; 70 | }); 71 | phantom.exit((parseInt(failedNum, 10) > 0) ? 1 : 0); 72 | }); 73 | } 74 | }); 75 | -------------------------------------------------------------------------------- /themes/create-ui/img/create-ui-bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/create-ui/img/create-ui-bg.png -------------------------------------------------------------------------------- /themes/create-ui/img/create-ui-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/create-ui/img/create-ui-logo.png -------------------------------------------------------------------------------- /themes/create-ui/img/create-ui-xdivider.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/create-ui/img/create-ui-xdivider.png -------------------------------------------------------------------------------- /themes/insertimage.css: -------------------------------------------------------------------------------- 1 | button.midgardCreate_button_img { 2 | background: url('../images/insert-image.gif') no-repeat !important; 3 | background-position: 0px 0px; 4 | } 5 | 6 | #midgardmvc-image-list input { 7 | padding: 2px; 8 | margin: 4px; 9 | width: 200px; 10 | } 11 | 12 | #midgardmvc-image-list .midgardmvc-image-list { 13 | padding: 0px; 14 | margin: 0px; 15 | } 16 | 17 | #midgardmvc-image-list .midgardmvc-image-list li { 18 | list-style: none; 19 | display: inline; 20 | } 21 | 22 | #midgardmvc-image-list .midgardmvc-image-list li img 23 | { 24 | margin: 2px; 25 | } 26 | 27 | #midgardmvc-image-upload h2 { 28 | margin-top: 0px; 29 | color: #000000; 30 | } 31 | 32 | #midgardmvc-image-upload { 33 | text-align: center; 34 | padding-bottom: 6px; 35 | background-color: #ffffff; 36 | border-radius: 6px; 37 | } 38 | 39 | div.midgardmvc-image-hover { 40 | background-color: #67cc08 !important; 41 | } 42 | -------------------------------------------------------------------------------- /themes/midgard-geo/pin-regular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-geo/pin-regular.png -------------------------------------------------------------------------------- /themes/midgard-geo/pin-selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-geo/pin-selected.png -------------------------------------------------------------------------------- /themes/midgard-geo/pin-unrelevant-grey.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-geo/pin-unrelevant-grey.png -------------------------------------------------------------------------------- /themes/midgard-geo/pin-unrelevant.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-geo/pin-unrelevant.png -------------------------------------------------------------------------------- /themes/midgard-notifications/leftright.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-notifications/leftright.png -------------------------------------------------------------------------------- /themes/midgard-notifications/midgardnotif.css: -------------------------------------------------------------------------------- 1 | .midgardNotifications-container { 2 | width: 280px; 3 | z-index: 9999; 4 | color: white; 5 | position: relative; 6 | } 7 | * html .midgardNotifications-container { 8 | position: absolute; 9 | } 10 | 11 | .midgardNotifications-item-normal .midgardNotifications-item-inner, 12 | .midgardNotifications-item-binded .midgardNotifications-item-inner { 13 | height: auto; 14 | background: #333; 15 | opacity: 0.9; 16 | -moz-border-radius: 10px; 17 | -webkit-border-radius: 10px; 18 | color: #eee; 19 | /* padding-top: 20px; 20 | padding-bottom: 20px; 21 | padding-left: 6px; 22 | padding-right: 6px;*/ 23 | padding: 5px; 24 | font-family: lucida Grande; 25 | font-size: 14px; 26 | border: 2px solid #999; 27 | display: block; 28 | position: relative; 29 | margin: 0 0 12px 0; 30 | z-index: 9998; 31 | } 32 | 33 | .midgardNotifications-item-binded .midgardNotifications-item-inner { 34 | left: 0; 35 | top: 0; 36 | } 37 | .midgardNotifications-item-inner .midgardNotifications-content { 38 | padding:10px; 39 | font-size:14px; 40 | text-shadow:none; 41 | } 42 | 43 | .midgardNotifications-title { 44 | text-align: left; 45 | } 46 | 47 | .midgardNotifications-disregard { 48 | width: 22px; 49 | height: 22px; 50 | position: absolute; 51 | top: -7px; right: -7px; 52 | cursor: pointer; 53 | -moz-border-radius: 22px; 54 | background: #000; 55 | } 56 | 57 | .midgardNotifications-arrow { 58 | position:absolute; 59 | background-color:transparent; 60 | background-repeat:no-repeat; 61 | } 62 | .midgardNotifications-arrow_T, 63 | .midgardNotifications-arrow_B, 64 | .midgardNotifications-arrow_TL, 65 | .midgardNotifications-arrow_TR, 66 | .midgardNotifications-arrow_BL, 67 | .midgardNotifications-arrow_BR{ 68 | background-image:url(topbottom.png); 69 | width:13px; 70 | height:7px; 71 | } 72 | .midgardNotifications-arrow_L, 73 | .midgardNotifications-arrow_R, 74 | .midgardNotifications-arrow_LT, 75 | .midgardNotifications-arrow_LB, 76 | .midgardNotifications-arrow_RT, 77 | .midgardNotifications-arrow_RB{ 78 | background-image:url(leftright.png); 79 | width:7px; 80 | height:13px; 81 | } 82 | .midgardNotifications-arrow_T{ 83 | background-position:0px -7px; 84 | top:-7px; 85 | left:50%; 86 | margin-left:-3.5px; 87 | } 88 | .midgardNotifications-arrow_TL{ 89 | background-position:0px -7px; 90 | top:-7px; 91 | left:5px; 92 | } 93 | .midgardNotifications-arrow_TR{ 94 | background-position:0px -7px; 95 | top:-7px; 96 | right:5px; 97 | } 98 | .midgardNotifications-arrow_B{ 99 | background-position:0px 0px; 100 | bottom:-7px; 101 | left:50%; 102 | margin-left:-3.5px; 103 | } 104 | .midgardNotifications-arrow_BL{ 105 | background-position:0px 0px; 106 | bottom:-7px; 107 | left:5px; 108 | } 109 | .midgardNotifications-arrow_BR{ 110 | background-position:0px 0px; 111 | bottom:-7px; 112 | right:5px; 113 | } 114 | .midgardNotifications-arrow_L{ 115 | background-position:-7px 0px; 116 | top:50%; 117 | margin-top:-6.5px; 118 | left:-7px; 119 | } 120 | .midgardNotifications-arrow_LT{ 121 | background-position:-7px 0px; 122 | top:5px; 123 | left:-7px; 124 | } 125 | .midgardNotifications-arrow_LB{ 126 | background-position:-7px 0px; 127 | bottom:5px; 128 | left:-7px; 129 | } 130 | .midgardNotifications-arrow_R{ 131 | background-position:0px 0px; 132 | top:50%; 133 | margin-top:-6.5px; 134 | right:-7px; 135 | } 136 | .midgardNotifications-arrow_RT{ 137 | background-position:0px 0px; 138 | top:5px; 139 | right:-7px; 140 | } 141 | .midgardNotifications-arrow_RB{ 142 | background-position:0px 0px; 143 | bottom:5px; 144 | right:-7px; 145 | } 146 | -------------------------------------------------------------------------------- /themes/midgard-notifications/topbottom.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-notifications/topbottom.png -------------------------------------------------------------------------------- /themes/midgard-tags/close_button.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/close_button.png -------------------------------------------------------------------------------- /themes/midgard-tags/cornerclose.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/cornerclose.png -------------------------------------------------------------------------------- /themes/midgard-tags/cornersettings_large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/cornersettings_large.png -------------------------------------------------------------------------------- /themes/midgard-tags/cornersettings_large_hand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/cornersettings_large_hand.png -------------------------------------------------------------------------------- /themes/midgard-tags/cornersettings_small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/cornersettings_small.png -------------------------------------------------------------------------------- /themes/midgard-tags/settingsh2icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bergie/create/e7991609fa982947efc617465bf06860d01c5407/themes/midgard-tags/settingsh2icon.png -------------------------------------------------------------------------------- /themes/midgard-tags/tags.css: -------------------------------------------------------------------------------- 1 | /* Tagging */ 2 | /***************/ 3 | .hiddenfieldsContainer { 4 | z-index: 100; 5 | padding: 25px 38px 20px 20px; 6 | position: absolute; 7 | min-height: 30px; 8 | right: -25px; 9 | margin-top: -35px; 10 | } 11 | 12 | .hiddenfieldsToggle { 13 | background-image: url('cornersettings_small.png'); 14 | position: absolute; 15 | top: 0; 16 | right: 0; 17 | width: 106px; 18 | height: 92px; 19 | cursor: pointer; 20 | } 21 | 22 | .hiddenfieldsToggle:hover { 23 | background-image: url('cornersettings_large.png'); 24 | width: 157px; 25 | height: 136px; 26 | } 27 | 28 | .hiddenfields { 29 | background-color: black; 30 | width: 100%; 31 | display: none; 32 | border-radius: 3px; 33 | padding: 10px 10px 40px 10px; 34 | } 35 | 36 | .hiddenfields h2, 37 | .hiddenfields h3 { 38 | color: #A0A0A0; 39 | font-family: Helvetica, Arial; 40 | font-weight: bold; 41 | } 42 | 43 | .hiddenfields h2 { 44 | background: url('settingsh2icon.png') no-repeat left center; 45 | padding-left: 22px; 46 | padding-bottom: 0; 47 | font-size: 15px; 48 | } 49 | 50 | .hiddenfields h3 { 51 | font-size: 13px; 52 | margin: 10px 0 4px 0; 53 | } 54 | 55 | .hiddenfieldsCloseCorner { 56 | background: url('cornerclose.png') no-repeat left bottom; 57 | width: 106px; 58 | height: 72px; 59 | position: absolute; 60 | bottom: -10px; 61 | left: 0; 62 | display: none; 63 | cursor: pointer; 64 | } 65 | 66 | .hiddenfieldsCloseButton { 67 | background: url('close_button.png'); 68 | display: none; 69 | width: 25px; 70 | height: 25px; 71 | position: absolute; 72 | top: 15px; 73 | right: 6px; 74 | cursor: pointer; 75 | } 76 | 77 | #articleTagsWrapper { 78 | width: 400px; 79 | margin-top: 20px; 80 | } 81 | 82 | .tags_clear { 83 | clear:both; 84 | width:100%; 85 | height:0; 86 | } 87 | 88 | div.tagsinput { 89 | border: 0; 90 | background: none; 91 | width:300px; 92 | height:auto; 93 | overflow-y:auto; 94 | padding:3px; 95 | } 96 | 97 | div.tagsinput div { 98 | display: block; 99 | float: left; 100 | } 101 | 102 | div.tagsinput span.tag { 103 | border:1px solid #11a2bf; 104 | -moz-border-radius:2px; 105 | -webkit-border-radius:2px; 106 | display:block; 107 | float:left; 108 | text-decoration:none; 109 | background:#11accc; 110 | color:#fff; 111 | margin-right:5px; 112 | margin-bottom:5px; 113 | font-size:12px; 114 | padding: 2px 4px; 115 | cursor: pointer; 116 | } 117 | 118 | div.tagsinput span.tag a { 119 | font-weight: bold; 120 | color:#0b788e !important; 121 | text-decoration:none; 122 | font-size:13px; 123 | } 124 | 125 | div.tagsinput input, 126 | div.tagsinput input:focus { 127 | width:80px; 128 | font-size:12px; 129 | border: 0 !important; 130 | background:transparent !important; 131 | color:#fff !important; 132 | outline:0; 133 | margin:0 5px 5px 0; 134 | padding: 5px; 135 | -webkit-box-shadow: none !important; 136 | -moz-box-shadow: none !important; 137 | box-shadow: none !important; 138 | } 139 | 140 | .articleSuggestedTags { 141 | margin-bottom: 10px; 142 | } --------------------------------------------------------------------------------